Use observables instead of state in React components

Example of maintaining state with a simple observable in your own component:

import React from 'react';
import { observable } from 'mobx';
import { observer } from 'mobx-react';
@observer class MyComponent extends React.Component {
onClick = () => {
this.active = true;
// ...
};
@observable active = false;
render() {
return (
<a onClick={this.onClick} disabled={this.active}>click works only once</a>
);
}
}

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:

@observer class ParentComponent extends React.Component {
onOpenClick = () => {
this.overlayState.active = true;
};
@observable overlayState = {
active: false,
};
render() {
return (
<div>
<a onClick={this.onOpenClick}>open</a>
<Overlay observable={this.overlayState}>
</div>
);
}
}
@observer class Overlay extends React.Component {
onCloseClick = () => {
this.props.observable.active = false;
};
render() {
return (
{this.props.observable.active ?
<div>
<a onClick={this.onCloseClick}>close</a>
</div>
: null}
);
}
}
Overlay.propTypes = {
observable: React.PropTypes.shape({
active: React.PropTypes.bool.isRequired,
}).isRequired,
};

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.:

@observer class ParentComponent extends React.Component {
myMethod = () => {
action(() => {
this.observable1 = true;
this.observable2 = true;
})();
};
@observable observable1 = false;
@observable observable2 = false;
...
}

For more on this issue see: