btroncone / ngrx-store-localstorage

Simple syncing between @ngrx store and local storage
MIT License
613 stars 118 forks source link

Primitive values are unserialized to strings #86

Open yannickglt opened 6 years ago

yannickglt commented 6 years ago

My state looks like:

{
  "name": "John",
  "age": 12,
  "married": false,
  "children": []
}

And I use the metareducer as below:

localStorageSync({
  keys: ['name', 'age', 'married'],
  rehydrate: true
})(reducer)

It causes issues because it will create three different entries in the localStorage with the respective values "John", "12" and "false". During unserialization, these entries will remain strings as they are not parsed using JSON.parse (because they are not object-like values) and will equal "12" (I mean "12" as a string).

A possible alternative is to avoid storing primitive values, but it is quiet hard to keep in mind and does not look to be a bad practice (as I could not find any article about this topic). Another solution would be to always store states as objects instead of values. Another benefit would be to avoid multiplication of entries in the localStorage (one entry per state instead of one per key). The result in the localStorage would look like:

{"name":"John","age":12,"married":false}

Such a change would have incident on the way serialization is done and the main consequences would be:

I can create a PR if this suggestion looks viable to you and is wanted for the future.

firehist commented 6 years ago

Any update regarding this issue?

ernestomancebo commented 6 years ago

You could pass a reviver function that parses the non-string keys. Assuming that the state slice is called person, it should be something like this:


const personReviver = (key, value) => {
    switch (key) {
        case 'age':
            return Number(value);
        case 'married':
            return !!!value;
        default:
            return value;
    }
};

localStorageSync({ keys: [{ person: { reviver: personReviver } }], rehydrate: true })(reducer);
steffbeckers commented 11 months ago

You can try the following:

localStorageSync({
  keys: ['name', { age: { deserialize: parseInt } }, 'married'],
  rehydrate: true
})(reducer)