Use observables instead of state in React components
Example of maintaining state with a simple observable in your own component:
1
import React from 'react';
2
import { observable } from 'mobx';
3
import { observer } from 'mobx-react';
4
5
@observer class MyComponent extends React.Component {
6
onClick = () => {
7
this.active = true;
8
// ...
9
};
10
11
@observable active = false;
12
13
render() {
14
return (
15
<a onClick={this.onClick} disabled={this.active}>click works only once</a>
16
);
17
}
18
}
Copied!
Note that you are not passing an observable to the "a" component, you are passing a plain value (in this case a Boolean). When the observable changes, the render method above will be re-evaluated by React.
For components high in the component/DOM tree, re-evaluating their render method and all descendents' render methods can be expensive. It is therefore better to pass observable objects to child components, i.e. "dereference lately" as recommended on https://mobx.js.org/best/react-performance.html
Note that in non-production mode, this performance optimization will not occur when components declare propTypes, but it will work correctly in React production mode. See https://github.com/mobxjs/mobx-react/issues/56
Passing objects with observable properties also makes it easy to control the state of a child component both from within itself and from its parent. A common use case is a popup/overlay component that its parent needs to open and the overlay itself needs to be able to close:
1
@observer class ParentComponent extends React.Component {
2
onOpenClick = () => {
3
this.overlayState.active = true;
4
};
5
6
@observable overlayState = {
7
active: false,
8
};
9
10
render() {
11
return (
12
<div>
13
<a onClick={this.onOpenClick}>open</a>
14
<Overlay observable={this.overlayState}>
15
</div>
16
);
17
}
18
}
19
20
@observer class Overlay extends React.Component {
21
onCloseClick = () => {
22
this.props.observable.active = false;
23
};
24
25
render() {
26
return (
27
{this.props.observable.active ?
28
<div>
29
<a onClick={this.onCloseClick}>close</a>
30
</div>
31
: null}
32
);
33
}
34
}
35
36
Overlay.propTypes = {
37
observable: React.PropTypes.shape({
38
active: React.PropTypes.bool.isRequired,
39
}).isRequired,
40
};
Copied!
Note that ParentComponent's render method will not be re-evaluated when the active boolean is toggled, only Overlay's.

@action decorator in a React Component will break react-hot-loader

If, in your React component, you want to have a method that will update more than one observable, to make this atomic (and reduce re-renders), wrap the updates in an action() but do not use the @action decorator as currently this will cause an error in react-hot-loader (even if you edit and need to hot-reload a different component from the one with the decorator), i.e.:
1
@observer class ParentComponent extends React.Component {
2
myMethod = () => {
3
action(() => {
4
this.observable1 = true;
5
this.observable2 = true;
6
})();
7
};
8
9
@observable observable1 = false;
10
@observable observable2 = false;
11
...
12
}
Copied!
For more on this issue see:
Last modified 1yr ago