mobx-persist
mobx-persist copied to clipboard
Hydration deletes properties on sub-properties added by constructor
I have a stumbled on a problem with nested objects where I pass a value to the child, like so:
constructor(foo) {
this.someValue = foo;
}
After hydrating, the value is no longer there. Here's a reproducible example: https://codesandbox.io/s/qvp7x01x59
In the example I'm creating a store along with a child object created by another class. A value is passed to the child when instantiated, and is accessible directly after the store has been created. However, after being hydrated, it's lost.
Update: I'm guessing that this has to do with createSimpleSchema and not createModelSchema being used. I would gladly do a PR but I'm having trouble setting up environment and grasping the code since I'm not used to neither xcode nor typescript. It would be neat if the end result would be a third parameter being passed, something like:
@persist('object', Model, params)
@observable
new Model(params)
@AdamGerthel I have a same problem after updating mobx version from 4.2.1 to 5.5.2 on react-native 0.57.3 .
@JeffGuKang actually - I've come to the conclusion that this is due to the fact that in order to hydrate/re-hydrate, mobx-persist needs to be able to properly serialize the data in the store. This is basically impossible to do without knowing the structure/model of the data. So - there are two options, I think: Either make proper use of customArgs
(see https://github.com/pinqy520/mobx-persist#createconfig), which is not very well documented and might take a lot of time or drop mobx-persist entirely and switch to Mobx-state-tree instead.
Mobx-persist is simple to use for simple trees, but for complex situations, it's not as easy to use. I think that's basically one of the reasons why Mobx-state-tree was born in the first place.
You could of course also write your own solution, which might be a viable solution depending on how complex your data is.
@AdamGerthel I am using this module for list type having custom class as yours and it worked well before. I am considering how to resolve this problem and will share my solution after solving it even I am not sure what I choose now.
Anyway, Your comment is very helpful. Thank you for sharing information.
I solved by myself through autorun. My observable variable is list type that will has a class object having constructor. And it works well.
import {observable, computed, action, autorun, toJS, toJSON} from 'mobx';
class LetterStore {
@observable letterChannels = []; // LetterChannel
@observable isNew = false;
currentChannelId = null;
firstLetterCount = 0; // Use for Advertisement
setCurrentChannelId = (id) => {
this.currentChannelId = id;
}
constructor() {
let firstAutorun = true;
/**
* Autosave observable value
* TODO: Compare class params with each object in list
*/
autorun(async () => {
console.log('Autorun: ', firstAutorun, this.letterChannels);
if (firstAutorun) {
const json = await AsyncStorage.getItem("letterChannels");
if (json != null) {
this.letterChannels = JSON.parse(json);
}
firstAutorun = false;
} else {
const json = toJSON(this.letterChannels);
await AsyncStorage.setItem("letterChannels", json)
}
});
}
....
Actually, I think your use-case should work with Mobx-persist out of the box (but it depends on what your list contains). My issue was with sub-classes.
Anyway - another option would be to pass your existing data to the class constructor. You would have to fetch the data from storage before initiating the store, but I think it's a little nicer to keep that logic out of the class.
@AdamGerthel My observable list contains classes having sub classes. And I think your recommendation is better to use in production. Thank you :)
@JeffGuKang Glad I could help :)
If your problem grows (i.e. if your app becomes more complex) then I would recommend to consider switching to MobX State Tree since it can handle hydration out of the box.
For other's who stumble on mobx-persist problems and land here, I had trouble persisting JSON objects with lots of sub-properties. I hacked around this by persisting only strings from JSON.stringify(bigJSON), and then creating computed @get properties that return JSON.parse(bigJSONString) whenever I need it in the app. So long story short, I did the serializing myself into a string because I wasn't sure how to make the built in serializing work.