1

I want to store my mobx state in browser localStorage, so, if i use this approach https://stackoverflow.com/a/40326316
I save store with toJS, but don't know how to apply it. With extendObservable I get following error Error: [mobx] 'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead
Thanks in advance.

My approach is:

class MyStore {
...
  public async load() {
      const cached = await browser.storage.local.get("cache");
        const data = JSON.parse(cached["cached"]);
        Object.keys(data).forEach(x => {
          (this as any)[x] = (data as any)[x];
       });
...
}

But i think this is anitpattern.

FoxPro
  • 1,379
  • 3
  • 8
  • 20

2 Answers2

1

Are you sure extendObservable doesn't work. I've used something like this in my code.

class MyStore {
  async load() {
      const cached = await browser.storage.local.get("cache");
      mobx.extendObservable(this, cached);
  }
}

Edit:

This seems to be not working, you need to access the properties after extendObservable in order to reload them, you could use autorun but just use another method.

I've implemented load function based on a simple forEach; Try the following.

load = async () => {
    const { cache } = await JSON.parse(localStorage.getItem("cache"));

    Object.keys(cache).forEach(key => {
      this[key] = cache[key];
    });
  };

CodeSandbox https://codesandbox.io/s/late-snow-xppx0?ontsize=14&hidenavigation=1&theme=dark

Matt
  • 241
  • 1
  • 4
  • `Error: [mobx] 'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead` – FoxPro Jan 16 '20 at 08:17
  • Have you tried defining the data before loading? Like decorate(MyStore, { a: observable }. If you set the keys before the extendObservable It should work. – Matt Jan 16 '20 at 09:59
  • properties already defined in my class ```export class AppStore { @observable activeTab: number = 0; @observable currentUser: string = "";``` and so one – FoxPro Jan 17 '20 at 14:45
  • I wrote a codesandbox showing a thing I used without extendObservables, I just did did a forEach loop over the cache and set the data. Updated the answer as well. https://codesandbox.io/s/late-snow-xppx0?fontsize=14&hidenavigation=1&theme=dark – Matt Jan 19 '20 at 07:49
0

If you have a class, and "raw" json data, what i'm doing is to accept raw data in the constructor & then update the class properties.

For example, my raw data looks like this:

{
  users: [
    { id: 1, firstName: 'foo', lastName: 'bar', customer: { id: 1, name: 'bla' } },
    { id: 2, firstName: 'foo2', lastName: 'bar2', customer: { id: 2, name: 'customer' } },
  ];
}
class User {
  id;
  @observable firstName;
  @observable lastName;
  customer;

  constructor(rawUser) {
    this.id = rawUser.id;
    this.firstName = rawUser.firstName;
    this.lastName = rawUser.lastName;
    this.customer = new Customer(rawUser.customer);
  }
}
class UsersStore {
  @observable users = [];

  constructor(rawUsers) {
    this.users = rawUsers.map(rawUser => new User(rawUser));
  }
}

Then when I'm restoring the data I'm just using

const usersStore = new UsersStore(rawData.users);

The cool thing in this approach is the nesting handling, each "level" handles its part.

felixmosh
  • 20,379
  • 4
  • 36
  • 56