egghead.io lesson 1: observable & observer
Hosted on egghead.io

The observer function / decorator can be used to turn ReactJS components into reactive components. It wraps the component's render function in mobx.autorun to make sure that any data that is used during the rendering of a component forces a re-rendering upon change. It is available through the separate mobx-react package.

import { observer } from "mobx-react"

var timerData = observable({
  secondsPassed: 0

setInterval(() => {
}, 1000)

class Timer extends React.Component {
  render() {
    return <span>Seconds passed: {this.props.timerData.secondsPassed} </span>

ReactDOM.render(<Timer timerData={timerData} />, document.body)

Tip: when observer needs to be combined with other decorators or higher-order-components, make sure that observer is the innermost (first applied) decorator; otherwise it might do nothing at all.

Note that using @observer as decorator is optional, observer(class Timer ... { }) achieves exactly the same.

Gotcha: dereference values inside your components

MobX can do a lot, but it cannot make primitive values observable (although it can wrap them in an object see boxed observables). So not the values that are observable, but the properties of an object. This means that @observer actually reacts to the fact that you dereference a value. So in our above example, the Timer component would not react if it was initialized as follows:

React.render(<Timer timerData={timerData.secondsPassed} />, document.body)

In this snippet just the current value of secondsPassed is passed to the Timer, which is the immutable value 0 (all primitives are immutable in JS). That number won't change anymore in the future, so Timer will never update. It is the property secondsPassed that will change in the future, so we need to access it in the component. Or in other words: values need to be passed by reference and not by value.

ES5 support

In ES5 environments, observer components can be simple declared using observer(React.createClass({ .... See also the syntax guide

Stateless function components

The above timer widget could also be written using stateless function components that are passed through observer:

import { observer } from "mobx-react"

const Timer = observer(({ timerData }) => (
  <span>Seconds passed: {timerData.secondsPassed} </span>

Observable local component state

Just like normal classes, you can introduce observable properties on a component by using the @observable decorator. This means that you can have local state in components that doesn't need to be managed by React's verbose and imperative setState mechanism, but is as powerful. The reactive state will be picked up by render but will not explicitly invoke other React lifecycle methods except componentWillUpdate and componentDidUpdate. If you need other React lifecycle methods, just use the normal React state based APIs.

The example above could also have been written as:

import { observer } from "mobx-react"
import { observable } from "mobx"

class Timer extends React.Component {
  @observable secondsPassed = 0

  componentWillMount() {
    setInterval(() => {
    }, 1000)

  render() {
    return <span>Seconds passed: {this.secondsPassed} </span>

ReactDOM.render(<Timer />, document.body)

For more advantages of using observable local component state, see 3 reasons why I stopped using setState.

Observable local state in hook based components

To work with local observable state inside function components, the useLocalStore and useAsObservableSource hooks can be used.

Connect components to provided stores using inject

egghead.io lesson 8: inject stores with Provider

Tip: it is recommended to use React.creatContext instead

The mobx-react package also provides the Provider component that can be used to pass down stores using React's context mechanism. To connect to those stores, pass a list of store names to inject, which will make the stores available as props.

N.B. the syntax to inject stores has changed since mobx-react 4, always use inject(stores)(component) or @inject(stores) class Component.... Passing store names directly to observer is deprecated.


const colors = observable({
   foreground: '#000',
   background: '#fff'

const App = () =>
  <Provider colors={colors}>
     <app stuff... />

const Button = inject("colors")(observer(({ colors, label, onClick }) =>
  <button style={{
      color: colors.foreground,
      backgroundColor: colors.background

// later..
colors.foreground = 'blue';
// all buttons updated

See for more information the mobx-react docs.

When to apply observer?

The simple rule of thumb is: all components that render observable data. If you don't want to mark a component as observer, for example to reduce the dependencies of a generic component package, make sure you only pass it plain data.

With @observer there is no need to distinguish 'smart' components from 'dumb' components for the purpose of rendering. It is still a good separation of concerns for where to handle events, make requests etc. All components become responsible for updating when their own dependencies change. Its overhead is neglectable and it makes sure that whenever you start using observable data the component will respond to it. See this thread for more details.

Optimizing components

See the relevant section.

Characteristics of observer components

  • Observer only subscribe to the data structures that were actively used during the last render. This means that you cannot under-subscribe or over-subscribe. You can even use data in your rendering that will only be available at later moment in time. This is ideal for asynchronously loading data.
  • You are not required to declare what data a component will use. Instead, dependencies are determined at runtime and tracked in a very fine-grained manner.
  • Usually reactive components have no or little state, as it is often more convenient to encapsulate (view) state in objects that are shared with other component. But you are still free to use state.
  • @observer implements shouldComponentUpdate in the same way as PureComponent so that children are not re-rendered unnecessary.
  • Reactive components sideways load data; parent components won't re-render unnecessarily even when child components will.
  • @observer does not depend on React's context system.
  • In mobx-react@4+, the props object and the state object of an observer component are automatically made observable to make it easier to create @computed properties that derive from props inside such a component. If you have a reaction (i.e. autorun) inside your @observer component that must not be re-evaluated when the specific props it uses don't change, be sure to derefence those specific props for use inside your reaction (i.e. const myProp = props.myProp). Otherwise, if you reference props.myProp inside the reaction, then a change in any of the props will cause the reaction to be re-evaluated. For a typical use case with React-Router, see this article.