Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mobx doesn't observe classes in observable array

If I push a class instance into an observable array in MobX then it is not observed. However if I push a literal object into an observable array then it will be observed.

The docs for observable arrays say that

"all (future) values of the array will also be observable"

so I am trying to understand why this happens.

For example the following code can be run in node:

let mobx = require('mobx');

class TodoStore {
  constructor() {
    this.todos = mobx.observable.array([]);

    this.todos.push({title:'todo 1'});
    this.todos.push(new Todo('todo 2'));
  }
}

class Todo {
  constructor(title) {
    this.title = title;
  }
}

let store = new TodoStore();

console.log('***initial state***');
mobx.autorun(() => {
  if(store.todos.length > 0) {
    console.log('first todo:', store.todos[0].title);
    console.log('second todo:', store.todos[1].title);
  }
});

console.log('***Updating todo 1***');
store.todos[0].title = 'todo 1 updated';

console.log('***Updating todo 2***');
//Why doesn't this trigger the autorun?
store.todos[1].title = 'todo 2 updated'; 

this logs out

***initial state***
first todo: todo 1
second todo: todo 2
***Updating todo 1***
first todo: todo 1 updated
second todo: todo 2
***Updating todo 2***

Updating todo[1] does not trigger the autorun. Can anyone explain why? I know I could manually make the title property on the Todo class observable but I am wondering why I need to do that.

like image 233
rob Avatar asked Nov 10 '17 16:11

rob


1 Answers

Classes are never converted automatically, as to not interfere with any internal assumptions that class might have on itself. See the docs for observable objects :-D

If value is an object with a prototype, a JavaScript primitive or function, a Boxed Observable will be returned. MobX will not make objects with a prototype automatically observable; as that is the responsibility of its constructor function. Use extendObservable in the constructor, or @observable in its class definition instead.

In other words, do something like:

class Todo {
  constructor(title) {
    extendObservable(this, { title })
  }
}
like image 73
mweststrate Avatar answered Nov 03 '22 22:11

mweststrate