Evgeniy175
Evgeniy175

Reputation: 334

MobX: rerender after assign

Good day!

I have an parent component:

@observer
class ToDos extends Component {
  componentWillMount() {
    this.state = new State();
    this.onClearAllCompleted = this.onClearAllCompletedHandler.bind(this);
  }

  onClearAllCompletedHandler() {
    this.state.clearAllCompleted();
  }

  render() {
    const todos = this.state.todos;

    return (
      <Provider todos={todos}>
        {this.props.children}
        <ClearAllButton onClick={this.onClearAllCompleted} />
      </Provider>
    );
  }
}

And state class for it:

class TodosState {
  @observable todos = [
    { title: 'Sleep', completed: true },
    { title: 'Sleep more', completed: false },
    { title: 'Sleep more than before', completed: false }
  ];

  @action
  clearAllCompleted() {
    this.todos = this.todos.filter(todo => !todo.completed);
  }
}

When i try to clear all completed todos, it clears they with warning in browser console: MobX Provider: Provided store 'todos' has changed. Please avoid replacing stores as the change might not propagate to all children.

After this nothing happens: i have old rendered html ;(

So, i think that childrens has observable object of todos that references to one object and after assign in state i have different ref. Childs dont know about this, and their observable doesn't changed at all. So, what i can do in this case?

Upvotes: 0

Views: 894

Answers (1)

Petr
Petr

Reputation: 7365

The issue is in render method - on each re-render you pass new todos into Provider component. Provider component is tricky component which needs always the same props, but you pass different todos array each time.

Corrected code: pass the whole state object into Provider (this.state object is always the same in your example, just as Provider wants)

render() {

    return (
      <Provider store={this.state}>
        {this.props.children}
        <ClearAllButton onClick={this.onClearAllCompleted} />
      </Provider>
    );
}

By the way I recommend you replace componentWillMount() with constructor(). Constructor is better place for store initialization. Especially in next versions of React (16.0+) componentWillMount() might be called several times for the same instance before actual mount.

Upvotes: 2

Related Questions