Computed Values in MobX

MobX is a unique state management library which provides a simple way to make objects in JavaScript "observable" and react to changes on those observed values. A neat feature of MobX is the ability to mark a value as computed, which tells MobX that you'd like to derive a new value from one or more computed values.

import { computed, observable } from 'mobx';

class User {
  @observable firstName = 'Leonhard';
  @observable lastName  = 'Euler';

  @computed get fullName() {
    return `${this.firstName} ${this.lastName}`;
  }
}

In the example above, our user class has two observable values; firstName and lastName. Rather than adding to the modifiable state and creating an observable fullName property, it makes use of the @computed decorator to derive the full name. This works a lot like a spreadsheet formula, where the value of a spreadsheet cell depends on values from other cells. MobX will also cache the result of the computation, and won't recompute until one of the observable values it's using changes. Worthy of note, the computed value itself is also observable! It's observables all the way down! Computed values are awesome because they help to keep your modifiable state as minimal as possible, and are also highly optimized to only recompute when necessary. Surprisingly, this is all done very efficiently behind the scenes using a dependency graph made up of array pointers.

Under the hood, when you create a computed value, MobX runs the computation and keeps track of the "freshness" of the observable values that the computed value is derived from. Every observable used in the computation will register itself as a dependency of the computed value, and if the value changes, it will propagate a message to all of its dependencies letting them know that it is now "stale". Since those dependencies are potentially also being observed, they will recursively let their observers know that they are now "stale" as well. This results in a portion of the dependency graph being marked for re-computation, and allows MobX to know precisely which computed values need to run their computation again, and which can just continue returning their previously computed values.

MobX takes a lot of what we've learned about state management during the JavaScript renaissance and handles the crufty details for us. It has very few concepts, and once you get a handle of them they mostly stay out of your way. Comparing MobX to something like Flux or Redux, I'd say the concept of an observable dependency graph just "fits" better in my brain than actions, action creators, and reducers. I've found it to be pleasant, fast, and simple. Three adjectives that I rarely use when describing frontend libraries nowadays 😈

Thanks to Michel Westrate for his phenomenal deep dive on MobX which has been a tremendous resource for helping me understand what is going on behind the scenes.

Show Comments