MobX Recipes
  • Introduction
  • Observable vs @observable
  • Auto-save
  • Use extendObservable sparingly
  • Use observables instead of state in React components
  • Computed properties without @computed
  • Use computed.struct for computed objects
  • Observable-based routing
  • Be aware of short-circuited code in reactions
Powered by GitBook
On this page

Was this helpful?

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.

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

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

PreviousUse extendObservable sparinglyNextComputed properties without @computed

Last updated 4 years ago

Was this helpful?

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

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

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

https://mobx.js.org/best/react-performance.html
https://github.com/mobxjs/mobx-react/issues/56
action
https://github.com/mobxjs/mobx/issues/655
https://github.com/gaearon/react-proxy/issues/71