ngxs-labs / async-storage-plugin

⏱ WIP: Async Storage Plugin
MIT License
34 stars 13 forks source link

It first does a 'setItem' before getItem is resolved #25

Closed larscom closed 5 years ago

larscom commented 5 years ago

Hi,

I implemented the interface: AsyncStorageEngine, but everytime it does a 'setItem' first before getItem so you end up getting the initial state everytime the application loads...

image

marcus-sa commented 5 years ago

Does this still occur?

larscom commented 5 years ago

Does this still occur?

yeah

marcjulian commented 5 years ago

Can you provide an example for us to reproduce your issue?

larscom commented 5 years ago

This was an issue on my end. I only wanted to save a part of the state, i needed to make use of the serialize/deserialize methods. Now it serves my needs :)

Mathyn commented 5 years ago

@larscom I also want to save a part of the state but I do not understand how you can do this with the serialize/deserialize method. Shouldn't the key option be used for this?

larscom commented 5 years ago

@Mathyn i believe the 'key' option is the keyName of the state only..

What you need to do is, create a serialize function:

export function serialize({ statePart }: IState): string {
  return JSON.stringify({ statePart  });
}

And pass it to the forRoot function:

NgxsStoragePluginModule.forRoot({ serialize })

jcq commented 5 years ago

@larscom I'm not sure I understand; how did implementing serialize/deserialize resolve this for you?

I've implemented AsyncStorageEngine to use NgForage (an Angular wrapper for localForage), and data seems to be getting set correctly in IndexedDB using either default "@@STATE" key or by specifying the "key" array in NgxsAsyncStoragePluginModule config.

However, whenever I reload the page, I see my storage engine's setItem fn called with the default values prior to the getItem resolving (as stated in the original post). This means I never get proper rehydration upon reload, and effectively, no persistence whatsoever.

My code for the storage engine closely mirrors the IonicStorage-based example (See below).

import { Injectable } from '@angular/core';
import { Observable, from } from 'rxjs';
import { AsyncStorageEngine } from '@ngxs-labs/async-storage-plugin';
import { NgForage } from 'ngforage';

@Injectable({
    providedIn: 'root'
})
export class StorageService implements AsyncStorageEngine {
    constructor(private storage: NgForage) {}

    length(): Observable<number> {
        return from(this.storage.length());
    }

    getItem(key: any): Observable<any> {
        (async () => {
            console.log('getItem called', key);
            console.log('getItem resolved', await this.storage.getItem(key));
        })();

        return from(this.storage.getItem(key));
    }

    setItem(key: any, val: any): void {
        console.log('setItem', key, val);
        this.storage.setItem(key, val);
    }

    removeItem(key: any): void {
        this.storage.removeItem(key);
    }

    clear(): void {
        this.storage.clear();
    }

    key(val: number): Observable<string> {
        return from(this.storage.keys().then(keys => keys[val]));
    }
}

I have implemented serialize/deserialize like so (since I don't need them to be stored as strings):

export function serialize<T>(input: T): T {
    return input;
}

export function deserialize<T>(val: T): T {
    return val;
}

Is it possible that this is related to #67 ?

I'd love it if I was just missing something simple...