Mobx: @computed and "Error: [mobx] Invariant failed"

Created on 14 Apr 2016  路  3Comments  路  Source: mobxjs/mobx

I get the following error: Error: [mobx] Invariant failed: It is not allowed to change the state when a computed value is being evaluated.
I am new to MobX, so there is some trial an error here. I think I am using @computed and autorun() incorrectly. I have a case with three classes and I will try to illustrate it.

class A {   
  @observable r = [];
  constructor( dao ) {
    this._dao = dao;
    autorun( () => this.findSomething() );
  }
  findSomething() {
    ...
    // this line causes the error. With or without then(...) does not matter.
    // commenting the line out removes error and renders properly
    this._dao.findSomething.then(...)
  }
}

class Dao {
  constructor( db ) {
    this._db = db;
  }
  // returns promise
  @computed get findSomething() {
    return this._db.somecollection.find(...).then(...)
  }
}

class B {
  @observerble data = [];
  constructor() {
    autorun( () => this.loadData() );
  }
  // but this function throws the above invariant error
  loadData() {
    db.findData().then(...)
  }
}

The classes A and B are used by two different React components and are renderd together. The goal is to have Dao use B.data, load reactively data from a local db, until A.r is changed and triggers a re-render.
What should be handled with autorun() and setting an @observable and what should be @computed?

Thanks

Most helpful comment

That error means you changing observable state inside @computed getter. You must have removed it from your code snippet, but I suspect there is something like (assuming, that _db.somecollection.find() works synchronously):

  @computed get findSomething() {
    return this._db.somecollection.find(...).then(something => { this.r = something; return something; })
  }

Just use autorun for side effects and observable state modifications

All 3 comments

That error means you changing observable state inside @computed getter. You must have removed it from your code snippet, but I suspect there is something like (assuming, that _db.somecollection.find() works synchronously):

  @computed get findSomething() {
    return this._db.somecollection.find(...).then(something => { this.r = something; return something; })
  }

Just use autorun for side effects and observable state modifications

And assuming that your .then() is not like Pomise.then(), otherwise @computed get returning promise doesn't makes sense to me

That error means you changing observable state inside @computed getter.

Thanks, that clarifies it. I wanted the Dao to be reactive, but I changed it. I use autorun() in A to call the promise returning Dao.findSomething().

Was this page helpful?
0 / 5 - 0 ratings