Mobx: extendObservable doesn't help when we need to introduce new properties to the model-it doesn't rerender mobx-react components

Created on 16 Apr 2016  路  2Comments  路  Source: mobxjs/mobx

I would kind of expect that if I run this small app:

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {observable, extendObservable} from 'mobx';
import {observer} from 'mobx-react';
import DevTools from 'mobx-react-devtools';

const obs = observable({})

setTimeout(() => {
  extendObservable(obs, {num: 4}) // doesn't rerender
}, 100)

@observer
class TimerView extends Component {
     render() {
        return (
            <div>
                num: {obs.num}
                <DevTools />
            </div>
        );
     }

};

ReactDOM.render(<TimerView/>, document.getElementById('root'));

that after 100ms it gives me:

num: 4

But it doesn't. It just gives me

num:

Could there be a way to fix this?
Maybe we could have an extendObservable on mobx-react API which would call extendObservable() from mobx and would also rerender any mounted observer component?

If not, maybe just mention in the docs, that extendObservable doesn't really help when your rendering loop is already running and that manual rerender is needed,

BTW, sorry about the complex sample, I was trying out bunch of other things and forgot to reduce it before posting this issue.

Most helpful comment

I just ran into a similar issue where I was trying to use an object as a map. I'm not sure if this is relevant in your case, but the observable map worked really well for me.

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {observable, extendObservable, map} from 'mobx';
import {observer} from 'mobx-react';
import DevTools from 'mobx-react-devtools';

const obs = map()

setTimeout(() => {
  obs.set('num', 4)
}, 100)

@observer
class TimerView extends Component {
     render() {
        return (
            <div>
                num: {obs.has('num') ? obs.get('num') : ''}
                <DevTools />
            </div>
        );
     }

};

ReactDOM.render(<TimerView/>, document.getElementById('root'));

The above example is somewhat abusing Map, but it gets the point across.

All 2 comments

I just ran into a similar issue where I was trying to use an object as a map. I'm not sure if this is relevant in your case, but the observable map worked really well for me.

import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {observable, extendObservable, map} from 'mobx';
import {observer} from 'mobx-react';
import DevTools from 'mobx-react-devtools';

const obs = map()

setTimeout(() => {
  obs.set('num', 4)
}, 100)

@observer
class TimerView extends Component {
     render() {
        return (
            <div>
                num: {obs.has('num') ? obs.get('num') : ''}
                <DevTools />
            </div>
        );
     }

};

ReactDOM.render(<TimerView/>, document.getElementById('root'));

The above example is somewhat abusing Map, but it gets the point across.

@jbrantly is right, you cannot observe not yet existing properties and be notified about them, except when using maps.

Note also that if you would have triggered the TimerView by any some other means to re-render after the timeout. Future changes to num will be picked up as the observer list is re-established after each render.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mdebbar picture mdebbar  路  3Comments

joey-lucky picture joey-lucky  路  3Comments

etinif picture etinif  路  3Comments

kmalakoff picture kmalakoff  路  4Comments

giacomorebonato picture giacomorebonato  路  3Comments