# Mobx
>
---
# Resources
- [Ten minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)
- How MobX works: [In depth explanation of MobX](https://medium.com/@mweststrate/becoming-fully-reactive-an-in-depth-explanation-of-mobservable-55995262a254#.wnlo6bw8y)
- Clone the boilerplate repository containing the above example from: https://github.com/mweststrate/react-mobservable-boilerplate.
- Or fork this [JSFiddle](https://jsfiddle.net/mweststrate/wgbe4guu/).
## Related projects
- [mobx-connect](https://github.com/nightwolfz/mobx-connect) MobX @connect decorator for react components. Similar to redux's @connect.
- [rfx-stack](https://github.com/foxhound87/rfx-stack) RFX Stack - Universal App featuring: React + Feathers + MobX
- [mobx-reactor](https://github.com/amsb/mobx-reactor) Connect MobX data stores to functional stateless React components with async actions and unidirectional data flow.
- [mobx-model](https://github.com/ikido/mobx-model) Simplify mobx data stores that mimic backend models
- [rx-mobx](https://github.com/chicoxyzzy/rx-mobx) Convert MobX observables to RxJS and vice versa
## More examples
A nice list is WIP, but see this [github issue](https://github.com/mobxjs/mobx/issues/104) for a list of example projects, including routing, authorization, server side rendering etc.
- [TodoMVC using MobX and React](https://github.com/mweststrate/mobx-todomvc)
- The [ports of the _Notes_ and _Kanban_ examples](https://github.com/survivejs/mobservable-demo) from the book "SurviveJS - Webpack and React" to mobservable.
- A simple webshop using [React + mobx](https://jsfiddle.net/mweststrate/46vL0phw) or [JQuery + mobx](http://jsfiddle.net/mweststrate/vxn7qgdw).
- [Simple timer](https://jsfiddle.net/mweststrate/wgbe4guu/) application in JSFiddle.
- [Simple ES5 MobX examples](https://github.com/mattruby/mobx-examples) Bite sized MobX examples all setup to run in jsFiddle.
## Philosophy
- [Making React reactive: the pursuit of high performing, easily maintainable React apps](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/)
- [SurviveJS interview on Mobservable, React and Flux](http://survivejs.com/blog/mobservable-interview/)
- [Pure rendering in the light of time and state](https://medium.com/@mweststrate/pure-rendering-in-the-light-of-time-and-state-4b537d8d40b1)
- [Official homepage](http://mobxjs.github.io/mobx/)
---
---
title: About this documentation
sidebar_label: About this documentation
hide_title: true
---
# About this documentation
It follows the principle that the most commonly used concepts are
introduced before specialized information. This applies to the headings in the table
of concepts as well as the pages under those headings.
We've marked the sections and concepts that are more advanced with the {🚀} marker. You likely won't have to understand them until you will have a special use case, and can use MobX very effectively without knowing about them. Feel free to skip them and move on to the next section!
The documentation has been rewritten for MobX 6. For older versions of MobX, it can be found [here](https://github.com/mobxjs/mobx/tree/mobx4and5/docs).
All the principles are the same, and the API is largely the same. The main difference is that before MobX 6, [decorators](https://github.com/mobxjs/mobx/blob/mobx4and5/docs/best/decorators.md) were the recommended syntax to write MobX enhanced classes.
A summary of the documentation can be downloaded as cheat sheet:
## Guided tour
To get an overall idea of how to use MobX with React, read through the current _Introduction_ heading, in particular [The gist of MobX](the-gist-of-mobx.md) section.
It will introduce you to the most important principles, APIs and how they relate.
You should be ready to use MobX once you read this!
Here are a few suggestions about the next things to check out:
- Try the [10 minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)
- [React integration](react-integration.md)
- [`makeObservable` / `makeAutoObservable`](observable-state.md)
- Learn about [actions](actions.md), which includes a discussion on asynchronous actions
- The basics of [computeds](computeds.md)
- Read about [`autorun`](reactions.md#autorun), if only because it's used in the examples
- To get an idea on how to organize your application's data stores, check out [Defining data stores](defining-data-stores.md)
- If the behavior of MobX confuses you, it's useful to check out [Understanding reactivity](understanding-reactivity.md)
- Get a [quick overview of the API](api.md), also linked in the top navigation bar
This should give you a good understanding of the day-to-day uses of MobX. There is plenty more available for you to read at your own leisure.
---
---
title: Updating state using actions
sidebar_label: Actions
hide_title: true
---
# Updating state using actions
Usage:
- `action` _(annotation)_
- `action(fn)`
- `action(name, fn)`
- `@action` _(method / field decorator)_
All applications have actions. An action is any piece of code that modifies the state. In principle, actions always happen in response to an event. For example, a button was clicked, some input changed, a websocket message arrived, etc.
MobX requires that you declare your actions, although [`makeAutoObservable`](observable-state.md#makeautoobservable) can automate much of this job. Actions help you structure your code better and offer the following performance benefits:
1. They are run inside [transactions](api.md#transaction). No reactions will be run until the outer-most action has finished, guaranteeing that intermediate or incomplete values produced during an action are not visible to the rest of the application until the action has completed.
2. By default, it is not allowed to change the state outside of actions. This helps to clearly identify in your code base where the state updates happen.
The `action` annotation should only be used on functions that intend to _modify_ the state. Functions that derive information (performing lookups or filtering data) should _not_ be marked as actions, to allow MobX to track their invocations. `action` annotated members will be non-enumerable.
## Examples
```javascript
import { makeObservable, observable, action } from "mobx"
class Doubler {
value = 0
constructor() {
makeObservable(this, {
value: observable,
increment: action
})
}
increment() {
// Intermediate states will not become visible to observers.
this.value++
this.value++
}
}
```
```javascript
import { observable, action } from "mobx"
class Doubler {
@observable accessor value = 0
@action
increment() {
// Intermediate states will not become visible to observers.
this.value++
this.value++
}
}
```
```javascript
import { makeAutoObservable } from "mobx"
class Doubler {
value = 0
constructor() {
makeAutoObservable(this)
}
increment() {
this.value++
this.value++
}
}
```
```javascript
import { makeObservable, observable, action } from "mobx"
class Doubler {
value = 0
constructor() {
makeObservable(this, {
value: observable,
increment: action.bound
})
}
increment() {
this.value++
this.value++
}
}
const doubler = new Doubler()
// Calling increment this way is safe as it is already bound.
setInterval(doubler.increment, 1000)
```
```javascript
import { observable, action } from "mobx"
const state = observable({ value: 0 })
const increment = action(state => {
state.value++
state.value++
})
increment(state)
```
```javascript
import { observable, runInAction } from "mobx"
const state = observable({ value: 0 })
runInAction(() => {
state.value++
state.value++
})
```
## Wrapping functions using `action`
To leverage the transactional nature of MobX as much as possible, actions should be passed as far outward as possible. It is good to mark a class method as an action if it modifies the state. It is even better to mark event handlers as actions, as it is the outer-most transaction that counts. A single unmarked event handler that calls two actions subsequently would still generate two transactions.
To help create action based event handlers, `action` is not only an annotation, but also a higher order function. It can be called with a function as an argument, and in that case it will return an `action` wrapped function with the same signature.
For example in React, an `onClick` handler can be wrapped as below.
```javascript
const ResetButton = ({ formState }) => (
)
```
For debugging purposes, we recommend to either name the wrapped function, or pass a name as the first argument to `action`.
**Note:** actions are untracked
Another feature of actions is that they are [untracked](api.md#untracked). When an action is called from inside a side effect or a computed value (very rare!), observables read by the action won't be counted towards the dependencies of the derivation
`makeAutoObservable`, `extendObservable` and `observable` use a special flavour of `action` called [`autoAction`](observable-state.md#autoAction),
that will determine at runtime if the function is a derivation or action.
## `action.bound`
Usage:
- `action.bound` _(annotation)_
The `action.bound` annotation can be used to automatically bind a method to the correct instance, so that `this` is always correctly bound inside the function.
**Tip:** use `makeAutoObservable(o, {}, { autoBind: true })` to bind all actions and flows automatically
```javascript
import { makeAutoObservable } from "mobx"
class Doubler {
value = 0
constructor() {
makeAutoObservable(this, {}, { autoBind: true })
}
increment() {
this.value++
this.value++
}
*flow() {
const response = yield fetch("http://example.com/value")
this.value = yield response.json()
}
}
```
## `runInAction`
Usage:
- `runInAction(fn)`
Use this utility to create a temporary action that is immediately invoked. Can be useful in asynchronous processes.
Check out the [above code block](#examples) for an example.
## Actions and inheritance
Only actions defined **on prototype** can be **overridden** by subclass:
```javascript
class Parent {
// on instance
arrowAction = () => {}
// on prototype
action() {}
boundAction() {}
constructor() {
makeObservable(this, {
arrowAction: action
action: action,
boundAction: action.bound,
})
}
}
class Child extends Parent {
// THROWS: TypeError: Cannot redefine property: arrowAction
arrowAction = () => {}
// OK
action() {}
boundAction() {}
constructor() {
super()
makeObservable(this, {
arrowAction: override,
action: override,
boundAction: override,
})
}
}
```
To **bind** a single _action_ to `this`, `action.bound` can be used instead of _arrow functions_.
See [**subclassing**](subclassing.md) for more information.
## Asynchronous actions
In essence, asynchronous processes don't need any special treatment in MobX, as all reactions will update automatically regardless of the moment in time they are caused.
And since observable objects are mutable, it is generally safe to keep references to them for the duration of an action.
However, every step (tick) that updates observables in an asynchronous process should be marked as `action`.
This can be achieved in multiple ways by leveraging the above APIs, as shown below.
For example, when handling promises, the handlers that update state should be actions or should be wrapped using `action`, as shown below.
Promise resolution handlers are handled in-line, but run after the original action finished, so they need to be wrapped by `action`:
```javascript
import { action, makeAutoObservable } from "mobx"
class Store {
githubProjects = []
state = "pending" // "pending", "done" or "error"
constructor() {
makeAutoObservable(this)
}
fetchProjects() {
this.githubProjects = []
this.state = "pending"
fetchGithubProjectsSomehow().then(
action("fetchSuccess", projects => {
const filteredProjects = somePreprocessing(projects)
this.githubProjects = filteredProjects
this.state = "done"
}),
action("fetchError", error => {
this.state = "error"
})
)
}
}
```
If the promise handlers are class fields, they will automatically be wrapped in `action` by `makeAutoObservable`:
```javascript
import { makeAutoObservable } from "mobx"
class Store {
githubProjects = []
state = "pending" // "pending", "done" or "error"
constructor() {
makeAutoObservable(this)
}
fetchProjects() {
this.githubProjects = []
this.state = "pending"
fetchGithubProjectsSomehow().then(this.projectsFetchSuccess, this.projectsFetchFailure)
}
projectsFetchSuccess = projects => {
const filteredProjects = somePreprocessing(projects)
this.githubProjects = filteredProjects
this.state = "done"
}
projectsFetchFailure = error => {
this.state = "error"
}
}
```
Any steps after `await` aren't in the same tick, so they require action wrapping.
Here, we can leverage `runInAction`:
```javascript
import { runInAction, makeAutoObservable } from "mobx"
class Store {
githubProjects = []
state = "pending" // "pending", "done" or "error"
constructor() {
makeAutoObservable(this)
}
async fetchProjects() {
this.githubProjects = []
this.state = "pending"
try {
const projects = await fetchGithubProjectsSomehow()
const filteredProjects = somePreprocessing(projects)
runInAction(() => {
this.githubProjects = filteredProjects
this.state = "done"
})
} catch (e) {
runInAction(() => {
this.state = "error"
})
}
}
}
```
```javascript
import { flow, makeAutoObservable, flowResult } from "mobx"
class Store {
githubProjects = []
state = "pending"
constructor() {
makeAutoObservable(this, {
fetchProjects: flow
})
}
// Note the star, this a generator function!
*fetchProjects() {
this.githubProjects = []
this.state = "pending"
try {
// Yield instead of await.
const projects = yield fetchGithubProjectsSomehow()
const filteredProjects = somePreprocessing(projects)
this.state = "done"
this.githubProjects = filteredProjects
return projects
} catch (error) {
this.state = "error"
}
}
}
const store = new Store()
const projects = await flowResult(store.fetchProjects())
```
## Using flow instead of async / await {🚀}
Usage:
- `flow` _(annotation)_
- `flow(function* (args) { })`
- `@flow` _(method decorator)_
The `flow` wrapper is an optional alternative to `async` / `await` that makes it easier to
work with MobX actions.
`flow` takes a [generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator) as its only input.
Inside the generator, you can chain promises by yielding them (instead of `await somePromise` you write `yield somePromise`).
The flow mechanism will then make sure the generator either continues or throws when a yielded promise resolves.
So `flow` is an alternative to `async` / `await` that doesn't need any further `action` wrapping. It can be applied as follows:
1. Wrap `flow` around your asynchronous function.
2. Instead of `async` use `function *`.
3. Instead of `await` use `yield`.
The [`flow` + generator function](#asynchronous-actions) example above shows what this looks like in practice.
Note that the `flowResult` function is only needed when using TypeScript.
Since decorating a method with `flow`, it will wrap the returned generator in a promise.
However, TypeScript isn't aware of that transformation, so `flowResult` will make sure that TypeScript is aware of that type change.
`makeAutoObservable` and friends will automatically infer generators to be `flow`s. `flow` annotated members will be non-enumerable.
{🚀} **Note:** using flow on object fields
`flow`, like `action`, can be used to wrap functions directly. The above example could also have been written as follows:
```typescript
import { flow, makeObservable, observable } from "mobx"
class Store {
githubProjects = []
state = "pending"
constructor() {
makeObservable(this, {
githubProjects: observable,
state: observable,
})
}
fetchProjects = flow(function* (this: Store) {
this.githubProjects = []
this.state = "pending"
try {
// yield instead of await.
const projects = yield fetchGithubProjectsSomehow()
const filteredProjects = somePreprocessing(projects)
this.state = "done"
this.githubProjects = filteredProjects
} catch (error) {
this.state = "error"
}
})
}
const store = new Store()
const projects = await store.fetchProjects()
```
The upside is that we don't need `flowResult` anymore, the downside is that `this` needs to be typed to make sure its type is inferred correctly.
## `flow.bound`
Usage:
- `flow.bound` _(annotation)_
The `flow.bound` annotation can be used to automatically bind a method to the correct instance, so that `this` is always correctly bound inside the function.
Similary to actions, flows can be bound by default using [`autoBind` option](#auto-bind).
## Cancelling flows {🚀}
Another neat benefit of flows is that they are cancellable.
The return value of `flow` is a promise that resolves with the value that is returned from the generator function in the end.
The returned promise has an additional `cancel()` method that will interrupt the running generator and cancel it.
Any `try` / `finally` clauses will still be run.
## Disabling mandatory actions {🚀}
By default, MobX 6 and later require that you use actions to make changes to the state.
However, you can configure MobX to disable this behavior. Check out the [`enforceActions`](configuration.md#enforceactions) section.
For example, this can be quite useful in unit test setup, where the warnings don't always have much value.
---
---
title: Analyzing reactivity
sidebar_label: Analyzing reactivity {🚀}
hide_title: true
---
# Analyzing reactivity {🚀}
# Using `trace` for debugging
Trace is a small utility that helps you find out why your computed values, reactions or components are re-evaluating.
It can be used by simply importing `import { trace } from "mobx"`, and then putting it inside a reaction or computed value.
It will print why it is re-evaluating the current derivation.
Optionally it is possible to automatically enter the debugger by passing `true` as the last argument.
This way the exact mutation that causes the reaction to re-run will still be in stack, usually ~8 stack frames up. See the image below.
In debugger mode, the debug information will also reveal the full derivation tree that is affecting the current computation / reaction.


## Live examples
Simple [CodeSandbox `trace` example](https://codesandbox.io/s/trace-dnhbz?file=/src/index.js:309-338).
[Here's a deployed example](https://csb-nr58ylyn4m-hontnuliaa.now.sh/) for exploring the stack.
Make sure to play with the chrome debugger's blackbox feature!
## Usage examples
There are different ways of calling `trace()`, some examples:
```javascript
import { observer } from "mobx-react"
import { trace } from "mobx"
const MyComponent = observer(() => {
trace(true) // Enter the debugger whenever an observable value causes this component to re-run.
return
{this.props.user.name}
})
```
Enable trace by using the `reaction` argument of a reaction / autorun:
```javascript
mobx.autorun("logger", reaction => {
reaction.trace()
console.log(user.fullname)
})
```
Pass in the property name of a computed property:
```javascript
trace(user, "fullname")
```
# Introspection APIs
The following APIs might come in handy if you want to inspect the internal state of MobX while debugging, or want to build cool tools on top of MobX.
Also relevant are the various [`isObservable*` APIs](api.md#isobservable).
### `getDebugName`
Usage:
- `getDebugName(thing, property?)`
Returns a (generated) friendly debug name of an observable object, property, reaction etc. Used for example by the [MobX developer tools](https://github.com/mobxjs/mobx-devtools).
### `getDependencyTree`
Usage:
- `getDependencyTree(thing, property?)`.
Returns a tree structure with all observables the given reaction / computation currently depends upon.
### `getObserverTree`
Usage:
- `getObserverTree(thing, property?)`.
Returns a tree structure with all reactions / computations that are observing the given observable.
### `getAtom`
Usage:
- `getAtom(thing, property?)`.
Returns the backing _Atom_ of a given observable object, property, reaction etc.
# Spy
Usage:
- `spy(listener)`
Registers a global spy listener that listens to all events that happen in MobX.
It is similar to attaching an `observe` listener to _all_ observables at once, but also notifies about running (trans/re)actions and computations.
Used for example by the [MobX developer tools](https://github.com/mobxjs/mobx-devtools).
Example usage of spying all actions:
```javascript
spy(event => {
if (event.type === "action") {
console.log(`${event.name} with args: ${event.arguments}`)
}
})
```
Spy listeners always receive one object, which usually has at least a `type` field. The following events are emitted by default by spy:
| Type | observableKind | Other fields | Nested |
| ------------------------------- | -------------- | -------------------------------------------------------------- | ------ |
| action | | name, object (scope), arguments[] | yes |
| scheduled-reaction | | name | no |
| reaction | | name | yes |
| error | | name, message, error | no |
| add,update,remove,delete,splice | | Check out [Intercept & observe {🚀}](intercept-and-observe.md) | yes |
| report-end | | spyReportEnd=true, time? (total execution time in ms) | no |
The `report-end` events are part of an earlier fired event that had `spyReportStart: true`.
This event indicates the end of an event and this way groups of events with sub-events are created.
This event might report the total execution time as well.
The spy events for observable values are identical to the events passed to `observe`.
In production builds, the `spy` API is a no-op as it will be minimized away.
Check out the [Intercept & observe {🚀}](intercept-and-observe.md#event-overview) section for an extensive overview.
---
---
title: MobX API Reference
sidebar_label: API
hide_title: true
---
# MobX API Reference
Functions marked with {🚀} are considered advanced, and should typically not be needed.
Consider downloading our handy cheat sheet that explains all important APIs on a single page:
## Core APIs
_These are the most important MobX APIs._
> Understanding [`observable`](#observable), [`computed`](#computed), [`reaction`](#reaction) and [`action`](#action) is enough to master and use MobX in your applications!
## Creating observables
_Making things observable._
### `makeObservable`
Usage: `makeObservable(target, annotations?, options?)`
([further information](observable-state.md#makeobservable))
Properties, entire objects, arrays, Maps and Sets can all be made observable.
### `makeAutoObservable`
Usage: `makeAutoObservable(target, overrides?, options?)`
([further information](observable-state.md#makeautoobservable))
Automatically make properties, objects, arrays, Maps and Sets observable.
### `extendObservable`
{🚀} Usage: `extendObservable(target, properties, overrides?, options?)`
Can be used to introduce new properties on the `target` object and make them observable immediately. Basically a shorthand for `Object.assign(target, properties); makeAutoObservable(target, overrides, options);`. However, existing properties on `target` won't be touched.
Old-fashioned constructor functions can nicely leverage `extendObservable`:
```javascript
function Person(firstName, lastName) {
extendObservable(this, { firstName, lastName })
}
const person = new Person("Michel", "Weststrate")
```
It is possible to use `extendObservable` to add observable fields to an existing object after instantiation, but be careful that adding an observable property this way is in itself not a fact that can be observed.
### `observable`
Usage: `observable(source, overrides?, options?)`, `observable` _(annotation)_ or `@observable accessor` _(field decorator)_.
([further information](observable-state.md#observable))
Clones an object and makes it observable. Source can be a plain object, array, Map or Set. By default, `observable` is applied recursively. If one of the encountered values is an object or array, that value will be passed through `observable` as well.
### `observable.object`
{🚀} Usage: `observable.object(source, overrides?, options?)`
([further information](observable-state.md#observable))
Alias for `observable(source, overrides?, options?)`. Creates a clone of the provided object and makes all of its properties observable.
### `observable.array`
{🚀} Usage: `observable.array(initialValues?, options?)`
Creates a new observable array based on the provided `initialValues`.
To convert observable arrays back to plain arrays, use the `.slice()` method, or check out [toJS](#tojs) to convert them recursively.
Besides all the language built-in array functions, the following goodies are available on observable arrays as well:
- `clear()` removes all current entries from the array.
- `replace(newItems)` replaces all existing entries in the array with new ones.
- `remove(value)` removes a single item by value from the array and returns `true` if the item was found and removed.
If the values in the array should not be turned into observables automatically, use the `{ deep: false }` option to make the array shallowly observable.
### `observable.map`
{🚀} Usage: `observable.map(initialMap?, options?)`
Creates a new observable [ES6 Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) based on the provided `initialMap`.
They are very useful if you don't want to react just to the change of a specific entry, but also to their addition and removal.
Creating observable Maps is the recommended approach for creating dynamically keyed collections if you don't have [enabled Proxies](configuration.md#proxy-support).
Besides all the language built-in Map functions, the following goodies are available on observable Maps as well:
- `toJSON()` returns a shallow plain object representation of this Map (use [toJS](#tojs) for a deep copy).
- `merge(values)` copies all entries from the provided `values` (plain object, array of entries or a string-keyed ES6 Map) into this Map.
- `replace(values)` replaces the entire contents of this Map with the provided `values`.
If the values in the Map should not be turned into observables automatically, use the `{ deep: false }` option to make the Map shallowly observable.
### `observable.set`
{🚀} Usage: `observable.set(initialSet?, options?)`
Creates a new observable [ES6 Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) based on the provided `initialSet`. Use it whenever you want to create a dynamic set where the addition and removal of values needs to be observed, but where values can appear only once in the entire collection.
If the values in the Set should not be turned into observables automatically, use the `{ deep: false }` option to make the Set shallowly observable.
Unlike Map keys, Set values are [not tracked individually](https://github.com/mobxjs/mobx/issues/2336#issuecomment-616128089).
### `observable.ref`
Usage: `observable.ref` _(annotation)_
([further information](observable-state.md#available-annotations))
Like the `observable` annotation, but only reassignments will be tracked. The assigned values themselves won't be made observable automatically. For example, use this if you intend to store immutable data in an observable field.
### `observable.shallow`
Usage: `observable.shallow` _(annotation)_
([further information](observable-state.md#available-annotations))
Like the `observable.ref` annotation, but for collections. Any collection assigned will be made observable, but the contents of the collection itself won't become observable.
### `observable.struct`
{🚀} Usage: `observable.struct` _(annotation)_
([further information](observable-state.md#available-annotations))
Like the `observable` annotation, except that any assigned value that is structurally equal to the current value will be ignored.
### `observable.deep`
{🚀} Usage: `observable.deep` _(annotation)_
([further information](observable-state.md#available-annotations))
Alias for the [`observable`](#observable) annotation.
### `observable.box`
{🚀} Usage: `observable.box(value, options?)`
All primitive values in JavaScript are immutable and hence per definition not observable.
Usually that is fine, as MobX can just make the _property_ that contains the value observable.
In rare cases, it can be convenient to have an observable _primitive_ that is not owned by an object.
For such cases, it is possible to create an observable _box_ that manages such a _primitive_.
`observable.box(value)` accepts any value and stores it inside a box. The current value can be accessed through `.get()` and updated using `.set(newValue)`.
```javascript
import { observable, autorun } from "mobx"
const cityName = observable.box("Vienna")
autorun(() => {
console.log(cityName.get())
})
// Prints: 'Vienna'
cityName.set("Amsterdam")
// Prints: 'Amsterdam'
```
If the values in the box should not be turned into observables automatically, use the `{ deep: false }` option to make the box shallowly observable.
---
## Actions
_An action is any piece of code that modifies the state._
### `action`
Usage: `action(fn)`, `action` _(annotation)_ or `@action` _(method / field decorator)_
([further information](actions.md))
Use on functions that intend to modify the state.
### `runInAction`
{🚀} Usage: `runInAction(fn)`
([further information](actions.md#runinaction))
Create a one-time action that is immediately invoked.
### `flow`
Usage: `flow(fn)`, `flow` _(annotation)_ or `@flow` _(generator method decorator)_
([further information](actions.md#using-flow-instead-of-async--await-))
MobX friendly replacement for `async` / `await` that supports cancellation.
### `flowResult`
Usage: `flowResult(flowFunctionResult)`
([further information](actions.md#using-flow-instead-of-async--await-))
For TypeScript users only. Utility that casts the output of the generator to a promise.
This is just a type-wise correction for the promise wrapping done by `flow`. At runtime it directly returns the inputted value.
---
## Computeds
_Computed values can be used to derive information from other observables._
### `computed`
Usage: `computed(fn, options?)`, `computed(options?)` _(annotation)_ or `@computed` _(getter decorator)_
([further information](computeds.md))
Creates an observable value that is derived from other observables, but won't be recomputed unless one of the underlying observables changes.
---
## React integration
_From the `mobx-react` / `mobx-react-lite` packages._
### `observer`
Usage: `observer(component)`
([further information](react-integration.md))
A higher order component you can use to make a functional or class based React component re-render when observables change.
### `Observer`
Usage: `{() => rendering}`
([further information](react-integration.md#callback-components-might-require-observer))
Renders the given render function, and automatically re-renders it once one of the observables used in the render function changes.
### `useLocalObservable`
Usage: `useLocalObservable(() => source, annotations?)`
([further information](react-integration.md#using-local-observable-state-in-observer-components))
Creates a new observable object using `makeObservable`, and keeps it around in the component for the entire life-cycle of the component.
---
## Reactions
_The goal of reactions is to model side effects that happen automatically._
### `autorun`
Usage: `autorun(() => effect, options?)`
([further information](reactions.md#autorun))
Reruns a function every time anything it observes changes.
### `reaction`
Usage: `reaction(() => data, data => effect, options?)`
([further information](reactions.md#reaction))
Reruns a side effect when any selected data changes.
### `when`
Usage: `when(() => condition, () => effect, options?)` or `await when(() => condition, options?)`
([further information](reactions.md#when))
Executes a side effect once when a observable condition becomes true.
---
## Utilities
_Utilities that might make working with observable objects or computed values more convenient. Less trivial utilities can also be found in the [mobx-utils](https://github.com/mobxjs/mobx-utils) package._
### `onReactionError`
{🚀} Usage: `onReactionError(handler: (error: any, derivation) => void)`
Attaches a global error listener, which is invoked for every error that is thrown from a _reaction_. This can be used for monitoring or test purposes.
### `intercept`
{🚀} Usage: `intercept(propertyName|array|object|Set|Map, listener)`
([further information](intercept-and-observe.md#intercept))
Intercepts changes before they are applied to an observable API. Returns a disposer function that stops the interception.
### `observe`
{🚀} Usage: `observe(propertyName|array|object|Set|Map, listener)`
([further information](intercept-and-observe.md#observe))
Low-level API that can be used to observe a single observable value. Returns a disposer function that stops the interception.
### `onBecomeObserved`
{🚀} Usage: `onBecomeObserved(observable, property?, listener: () => void)`
([further information](lazy-observables.md))
Hook for when something becomes observed.
### `onBecomeUnobserved`
{🚀} Usage: `onBecomeUnobserved(observable, property?, listener: () => void)`
([further information](lazy-observables.md))
Hook for when something stops being observed.
### `toJS`
Usage: `toJS(value)`
([further information](observable-state.md#converting-observables-back-to-vanilla-javascript-collections))
Recursively converts an observable object to a JavaScript _object_. Supports observable arrays, objects, Maps and primitives.
It does NOT recurse into non-observables, these are left as they are, even if they contain observables.
Computed and other non-enumerable properties are completely ignored and won't be returned.
For more complex (de)serialization scenarios, it is recommended to give classes a (computed) `toJSON` method, or use a serialization library like [serializr](https://github.com/mobxjs/serializr).
```javascript
const obj = mobx.observable({
x: 1
})
const clone = mobx.toJS(obj)
console.log(mobx.isObservableObject(obj)) // true
console.log(mobx.isObservableObject(clone)) // false
```
---
## Configuration
_Fine-tuning your MobX instance._
### `configure`
Usage: sets global behavior settings on the active MobX instance.
([further information](configuration.md))
Use it to change how MobX behaves as a whole.
---
## Collection utilities {🚀}
_They enable manipulating observable arrays, objects and Maps with the same generic API. This can be useful in [environments without `Proxy` support](configuration.md#limitations-without-proxy-support), but is otherwise typically not needed._
### `values`
{🚀} Usage: `values(array|object|Set|Map)`
([further information](collection-utilities.md))
Returns all values in the collection as an array.
### `keys`
{🚀} Usage: `keys(array|object|Set|Map)`
([further information](collection-utilities.md))
Returns all keys / indices in the collection as an array.
### `entries`
{🚀} Usage: `entries(array|object|Set|Map)`
([further information](collection-utilities.md))
Returns a `[key, value]` pair of every entry in the collection as an array.
### `set`
{🚀} Usage: `set(array|object|Map, key, value)`
([further information](collection-utilities.md))
Updates the collection.
### `remove`
{🚀} Usage: `remove(array|object|Map, key)`
([further information](collection-utilities.md))
Removes item from the collection.
### `has`
{🚀} Usage: `has(array|object|Map, key)`
([further information](collection-utilities.md))
Checks for membership in the collection.
### `get`
{🚀} Usage: `get(array|object|Map, key)`
([further information](collection-utilities.md))
Gets value from the collection with key.
---
## Introspection utilities {🚀}
_Utilities that might come in handy if you want to inspect the internal state of MobX, or want to build cool tools on top of MobX._
### `isObservable`
{🚀} Usage: `isObservable(array|object|Set|Map)`
Is the object / collection made observable by MobX?
### `isObservableProp`
{🚀} Usage: `isObservableProp(object, propertyName)`
Is the property observable?
### `isObservableArray`
{🚀} Usage: `isObservableArray(array)`
Is the value an observable array?
### `isObservableObject`
{🚀} Usage: `isObservableObject(object)`
Is the value an observable object?
### `isObservableSet`
{🚀} Usage: `isObservableSet(set)`
Is the value an observable Set?
### `isObservableMap`
{🚀} Usage: `isObservableMap(map)`
Is the value an observable Map?
### `isBoxedObservable`
{🚀} Usage: `isBoxedObservable(value)`
Is the value an observable box, created using `observable.box`?
### `isAction`
{🚀} Usage: `isAction(func)`
Is the function marked as an `action`?
### `isComputed`
{🚀} Usage: `isComputed(boxedComputed)`
Is this a boxed computed value, created using `computed(() => expr)`?
### `isComputedProp`
{🚀} Usage: `isComputedProp(object, propertyName)`
Is this a computed property?
### `trace`
{🚀} Usage: `trace()`, `trace(true)` _(enter debugger)_ or `trace(object, propertyName, enterDebugger?)`
([further information](analyzing-reactivity.md))
Should be used inside an observer, reaction or computed value. Logs when the value is invalidated, or sets the debugger breakpoint if called with _true_.
### `spy`
{🚀} Usage: `spy(eventListener)`
([further information](analyzing-reactivity.md#spy))
Registers a global spy listener that listens to all events that happen in MobX.
### `getDebugName`
{🚀} Usage: `getDebugName(reaction|array|Set|Map)` or `getDebugName(object|Map, propertyName)`
([further information](analyzing-reactivity.md#getdebugname))
Returns the (generated) friendly debug name for an observable or reaction.
### `getDependencyTree`
{🚀} Usage: `getDependencyTree(object, computedPropertyName)`
([further information](analyzing-reactivity.md#getdependencytree))
Returns a tree structure with all observables the given reaction / computation currently depends upon.
### `getObserverTree`
{🚀} Usage: `getObserverTree(array|Set|Map)` or `getObserverTree(object|Map, propertyName)`
([further information](analyzing-reactivity.md#getobservertree))
Returns a tree structure with all reactions / computations that are observing the given observable.
---
## Extending MobX {🚀}
_In the rare case you want to extend MobX itself._
### `createAtom`
{🚀} Usage: `createAtom(name, onBecomeObserved?, onBecomeUnobserved?)`
([further information](custom-observables.md))
Creates your own observable data structure and hooks it up to MobX. Used internally by all observable data types. Atom exposes two _report_ methods to notify MobX with when:
- `reportObserved()`: the atom has become observed, and should be considered part of the dependency tree of the current derivation.
- `reportChanged()`: the atom has changed, and all derivations depending on it should be invalidated.
### `getAtom`
{🚀} Usage: `getAtom(thing, property?)`
([further information](analyzing-reactivity.md#getatom))
Returns the backing atom.
### `transaction`
{🚀} Usage: `transaction(worker: () => any)`
_Transaction is a low-level API. It is recommended to use [`action`](#action) or [`runInAction`](#runinaction) instead._
Used to batch a bunch of updates without running any reactions until the end of the transaction. Like [`untracked`](#untracked), it is automatically applied by `action`, so usually it makes more sense to use actions than to use `transaction` directly.
It takes a single, parameterless `worker` function as an argument, and returns any value that was returned by it.
Note that `transaction` runs completely synchronously and can be nested. Only after completing the outermost `transaction`, the pending reactions will be run.
```javascript
import { observable, transaction, autorun } from "mobx"
const numbers = observable([])
autorun(() => console.log(numbers.length, "numbers!"))
// Prints: '0 numbers!'
transaction(() => {
transaction(() => {
numbers.push(1)
numbers.push(2)
})
numbers.push(3)
})
// Prints: '3 numbers!'
```
### `untracked`
{🚀} Usage: `untracked(worker: () => any)`
_Untracked is a low-level API. It is recommended to use [`reaction`](#reaction), [`action`](#action) or [`runInAction`](#runinaction) instead._
Runs a piece of code without establishing observers. Like `transaction`, `untracked` is automatically applied by `action`, so usually it makes more sense to use actions than to use `untracked` directly.
```javascript
const person = observable({
firstName: "Michel",
lastName: "Weststrate"
})
autorun(() => {
console.log(
person.lastName,
",",
// This untracked block will return the person's
// firstName without establishing a dependency.
untracked(() => person.firstName)
)
})
// Prints: 'Weststrate, Michel'
person.firstName = "G.K."
// Doesn't print!
person.lastName = "Chesterton"
// Prints: 'Chesterton, G.K.'
```
---
---
title: MobX Backers and Sponsors
hide_title: true
---
# MobX Backers and Sponsors
Thanks to your backers and sponsors for their generous support!
## Backers
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/mobx#backer)]
## Sponsors
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/mobx#sponsor)]
---
---
title: Analyzing reactivity
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../analyzing-reactivity.md)
---
---
title: Enabling decorators
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../enabling-decorators.md)
---
---
title: Defining data stores
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../defining-data-stores.md)
---
---
title: Understanding reactivity
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../understanding-reactivity.md)
---
---
title: Collection utilities
sidebar_label: Collection utilities {🚀}
hide_title: true
---
# Collection utilities {🚀}
They enable manipulating observable arrays, objects and Maps with the same generic API.
These APIs are fully reactive, which means that even [without `Proxy` support](configuration.md#limitations-without-proxy-support) new property declarations can be detected by MobX if `set` is used to add them, and `values` or `keys` are used to iterate over them.
Another benefit of `values`, `keys` and `entries` is that they return arrays rather than iterators, which makes it possible to, for example, immediately call `.map(fn)` on the results.
All that being said, a typical project has little reason to use these APIs.
Access:
- `values(collection)` returns an array of all the values in the collection.
- `keys(collection)` returns an array of all the keys in the collection.
- `entries(collection)` returns an array of all the entries `[key, value]` pairs in the collection.
Mutation:
- `set(collection, key, value)` or `set(collection, { key: value })` update the given collection with the provided key / value pair(s).
- `remove(collection, key)` removes the specified child from the collection. Splicing is used for arrays.
- `has(collection, key)` returns _true_ if the collection has the specified _observable_ property.
- `get(collection, key)` returns the child under the specified key.
If you use the access APIs in an environment without `Proxy` support, then also use the mutation APIs so they can detect the changes.
```javascript
import { autorun, get, set, observable, values } from "mobx"
const twitterUrls = observable.object({
Joe: "twitter.com/joey"
})
autorun(() => {
// Get can track not yet existing properties.
console.log(get(twitterUrls, "Sara"))
})
autorun(() => {
console.log("All urls: " + values(twitterUrls).join(", "))
})
set(twitterUrls, { Sara: "twitter.com/horsejs" })
```
---
---
title: Computeds with arguments
sidebar_label: Computeds with arguments {🚀}
hide_title: true
---
# Computeds with arguments {🚀}
The `computed` annotation can only be used on getters, which don't take arguments.
What about computations that do take arguments?
Take the below example of a React component that renders a specific `Item`,
and the application supports multi-selection.
How can we implement a derivation like `store.isSelected(item.id)`?
```javascript
import * as React from 'react'
import { observer } from 'mobx-react-lite'
const Item = observer(({ item, store }) => (
{item.title}
))
```
There are four ways in which we can approach this. You can try the solutions below in [this CodeSandbox](https://codesandbox.io/s/multi-selection-odup1?file=/src/index.tsx).
## 1. Derivations don't _need_ to be `computed`
A function doesn't need to be marked as `computed` in order for MobX to track it.
The above example would already work completely fine out of the box.
It is important to realize that computed values are only _caching points_.
If the derivations are pure (and they should be), having a getter or function without `computed` doesn't change the behavior, it is just slightly less efficient.
The above example works fine despite `isSelected` not being a `computed`. The `observer` component will detect and subscribe to any observables that were read by `isSelected` because the function executes as part of rendering that is tracked.
It is good to realize that all `Item` components, in this case, will respond to future selection changes,
as they all subscribe directly to the observables that capture the selection.
This is a worst-case example. In general, it is completely fine to have unmarked functions that derive information, and this is a good default strategy until numbers prove anything else should be done.
## 2. Close over the arguments
This is a more efficient implementation compared to the original.
```javascript
import * as React from 'react'
import { computed } from 'mobx'
import { observer } from 'mobx-react-lite'
const Item = observer(({ item, store }) => {
const isSelected = computed(() => store.isSelected(item.id)).get()
return (
{item.title}
)
})
```
We create a fresh computed value in the middle of a reaction. This works fine and does introduce that additional caching point, avoiding all components having to directly respond to every selection change.
The advantage of this approach is that the component itself will only re-render if the
`isSelected` state toggles, in which case we indeed have to re-render to swap the `className`.
The fact that we create a new `computed` in a next render is fine, this one will now become the caching
point and the previous one will be cleaned up nicely.
This is a great and advanced optimization technique.
## 3. Move the state
In this specific case the selection could also be stored as an `isSelected` observable on the `Item`. The selection in the store could then be expressed as a `computed` rather than an observable: `get selection() { return this.items.filter(item => item.isSelected) }`, and we don't need `isSelected` anymore.
## 4. Use computedFn {🚀}
Finally,
[`computedFn`](https://github.com/mobxjs/mobx-utils#computedfn) from `mobx-utils` can be used in the definition of `todoStore.selected` to automatically memoize `isSelected`.
It creates a function that memoizes the output for every combination of input arguments.
We recommend to not resort to this one too quickly. It is typical for memoization, that you will need to think about how many different arguments the function is going to be called with, before you can reason about the memory consumption.
It does however automatically clean up entries if their results aren't observed by any reaction, so it won't leak memory in normal circumstances.
Again, check out the [linked CodeSandbox](https://codesandbox.io/s/multi-selection-odup1?file=/src/index.tsx) to try this one out.
---
---
title: Deriving information with computeds
sidebar_label: Computeds
hide_title: true
---
# Deriving information with computeds
Usage:
- `computed` _(annotation)_
- `computed(options)` _(annotation)_
- `computed(fn, options?)`
- `@computed` _(getter decorator)_
- `@computed(options)` _(getter decorator)_
Computed values can be used to derive information from other observables.
They evaluate lazily, caching their output and only recomputing if one of the underlying observables has changed.
If they are not observed by anything, they suspend entirely.
Conceptually, they are very similar to formulas in spreadsheets, and can't be underestimated. They help in reducing the amount of state you have to store and are highly optimized. Use them wherever possible.
## Example
Computed values can be created by annotating JavaScript [getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) with `computed`.
Use `makeObservable` to declare a getter as computed. If you instead want all getters to be automatically declared as `computed`, you can use either `makeAutoObservable`, `observable` or `extendObservable`. Computed getters become non-enumerable.
To help illustrate the point of computed values, the example below relies on [`autorun`](reactions.md#autorun) from the [Reactions {🚀}](reactions.md) advanced section.
```javascript
import { makeObservable, observable, computed, autorun } from "mobx"
class OrderLine {
price = 0
amount = 1
constructor(price) {
makeObservable(this, {
price: observable,
amount: observable,
total: computed
})
this.price = price
}
get total() {
console.log("Computing...")
return this.price * this.amount
}
}
const order = new OrderLine(0)
const stop = autorun(() => {
console.log("Total: " + order.total)
})
// Computing...
// Total: 0
console.log(order.total)
// (No recomputing!)
// 0
order.amount = 5
// Computing...
// (No autorun)
order.price = 2
// Computing...
// Total: 10
stop()
order.price = 3
// Neither the computation nor autorun will be recomputed.
```
The above example nicely demonstrates the benefits of a `computed` value, it acts as a caching point.
Even though we change the `amount`, and this will trigger the `total` to recompute,
it won't trigger the `autorun`, as `total` will detect its output hasn't been affected, so there is no need to update the `autorun`.
In comparison, if `total` would not be annotated, the `autorun` would run its effect 3 times,
as it would directly depend on `total` and `amount`. [Try it out yourself](https://codesandbox.io/s/computed-3cjo9?file=/src/index.tsx).

This is the dependency graph that would be created for the above example.
## Rules
When using computed values there are a couple of best practices to follow:
1. They should not have side effects or update other observables.
2. Avoid creating and returning new observables.
3. They should not depend on non-observable values.
## Tips
**Tip:** computed values will be suspended if they are _not_ observed
It sometimes confuses people new to MobX, perhaps used to a library like [Reselect](https://github.com/reduxjs/reselect), that if you create a computed property but don't use it anywhere in a reaction, it is not memoized and appears to be recomputed more often than necessary.
For example, if we extended the above example with calling `console.log(order.total)` twice, after we called `stop()`, the value would be recomputed twice.
This allows MobX to automatically suspend computations that are not actively in use
to avoid unnecessary updates to computed values that are not being accessed. But if a computed property is _not_ in use by some reaction, then computed expressions are evaluated each time their value is requested, so they behave just like a normal property.
If you only fiddle around computed properties might not seem efficient, but when applied in a project that uses `observer`, `autorun`, etc., they become very efficient.
The following code demonstrates the issue:
```javascript
// OrderLine has a computed property `total`.
const line = new OrderLine(2.0)
// If you access `line.total` outside of a reaction, it is recomputed every time.
setInterval(() => {
console.log(line.total)
}, 60)
```
It can be overridden by setting the annotation with the `keepAlive` option ([try it out yourself](https://codesandbox.io/s/computed-3cjo9?file=/src/index.tsx)) or by creating a no-op `autorun(() => { someObject.someComputed })`, which can be nicely cleaned up later if needed.
Note that both solutions have the risk of creating memory leaks. Changing the default behavior here is an anti-pattern.
MobX can also be configured with the [`computedRequiresReaction`](configuration.md#computedrequiresreaction-boolean) option, to report an error when computeds are accessed outside of a reactive context.
**Tip:** computed values can have setters
It is possible to define a [setter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) for computed values as well. Note that these setters cannot be used to alter the value of the computed property directly,
but they can be used as an "inverse" of the derivation. Setters are automatically marked as actions. For example:
```javascript
class Dimension {
length = 2
constructor() {
makeAutoObservable(this)
}
get squared() {
return this.length * this.length
}
set squared(value) {
this.length = Math.sqrt(value)
}
}
```
{🚀} **Tip:** `computed.struct` for comparing output structurally
If the output of a computed value that is structurally equivalent to the previous computation doesn't need to notify observers, `computed.struct` can be used. It will make a structural comparison first, rather than a reference equality check, before notifying observers. For example:
```javascript
class Box {
width = 0
height = 0
constructor() {
makeObservable(this, {
width: observable,
height: observable,
topRight: computed.struct
})
}
get topRight() {
return {
x: this.width,
y: this.height
}
}
}
```
By default, the output of a `computed` is compared by reference. Since `topRight` in the above example will always produce a new result object, it is never going to be considered equal to a previous output. Unless `computed.struct` is used.
However, in the above example _we actually don't need `computed.struct`_!
Computed values normally only re-evaluate if the backing values change.
That's why `topRight` will only react to changes in `width` or `height`.
Since if any of those change, we would get a different `topRight` coordinate anyway. `computed.struct` would never have a cache hit and be a waste of effort, so we don't need it.
In practice, `computed.struct` is less useful than it sounds. Only use it if changes in the underlying observables can still lead to the same output. For example, if we were rounding the coordinates first, the rounded coordinates might be equal to the previously rounded coordinates even though the underlying values aren't.
Check out the [`equals`](#equals) option for further customizations on determining whether the output has changed.
{🚀} **Tip:** computed values with arguments
Although getters don't take arguments, several strategies to work with derived values that need arguments are discussed [here](computeds-with-args.md).
{🚀} **Tip:** create standalone computed values with `computed(expression)`
`computed` can also be invoked directly as a function, just like [`observable.box`](api.md#observablebox) creates a standalone computed value.
Use `.get()` on the returned object to get the current value of the computation.
This form of `computed` is not used very often, but in some cases where you need to pass a "boxed" computed value around it might prove itself useful, one such case is discussed [here](computeds-with-args.md).
## Options {🚀}
`computed` usually behaves the way you want it to out of the box, but it's possible to customize its behavior by passing in an `options` argument.
### `name`
This string is used as a debug name in the [Spy event listeners](analyzing-reactivity.md#spy) and [MobX developer tools](https://github.com/mobxjs/mobx-devtools).
### `equals`
Set to `comparer.default` by default. It acts as a comparison function for comparing the previous value with the next value. If this function considers the values to be equal, then the observers will not be re-evaluated.
This is useful when working with structural data and types from other libraries. For example, a computed [moment](https://momentjs.com/) instance could use `(a, b) => a.isSame(b)`. `comparer.structural` and `comparer.shallow` come in handy if you want to use structural / shallow comparison to determine whether the new value is different from the previous value, and as a result notify its observers.
Check out the [`computed.struct`](#computed-struct) section above.
#### Built-in comparers
MobX provides four built-in `comparer` methods which should cover most needs of the `equals` option of `computed`:
- `comparer.identity` uses the identity (`===`) operator to determine if two values are the same.
- `comparer.default` is the same as `comparer.identity`, but also considers `NaN` to be equal to `NaN`.
- `comparer.structural` performs deep structural comparison to determine if two values are the same.
- `comparer.shallow` performs shallow structural comparison to determine if two values are the same.
You can import `comparer` from `mobx` to access these methods. They can be used for `reaction` as well.
### `requiresReaction`
It is recommended to set this one to `true` on very expensive computed values. If you try to read its value outside of the reactive context, in which case it might not be cached, it will cause the computed to throw instead of doing an expensive re-evalution.
### `keepAlive`
This avoids suspending computed values when they are not being observed by anything (see the above explanation). Can potentially create memory leaks, similar to the ones discussed for [reactions](reactions.md#always-dispose-of-reactions).
---
---
title: Configuration
sidebar_label: Configuration {🚀}
hide_title: true
---
# Configuration {🚀}
MobX has several configurations depending on how you prefer to use it, which JavaScript engines you want to target, and whether you want MobX to hint at best practices.
Most configuration options can be set by using the `configure` method.
## Proxy support
By default, MobX uses proxies to make arrays and plain objects observable. Proxies provide the best performance and most consistent behavior across environments.
However, if you are targeting an environment that doesn't support proxies, proxy support has to be disabled.
Most notably this is the case when targeting Internet Explorer or React Native without using the Hermes engine.
Proxy support can be disabled by using `configure`:
```typescript
import { configure } from "mobx"
configure({
useProxies: "never"
})
```
Accepted values for the `useProxies` configuration are:
- `"always"` (**default**): MobX expects to run only in environments with [`Proxy` support](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) and it will error if such an environment is not available.
- `"never"`: Proxies are not used and MobX falls back on non-proxy alternatives. This is compatible with all ES5 environments, but causes various [limitations](#limitations-without-proxy-support).
- `"ifavailable"` (experimental): Proxies are used if they are available, and otherwise MobX falls back to non-proxy alternatives. The benefit of this mode is that MobX will try to warn if APIs or language features that wouldn't work in ES5 environments are used, triggering errors when hitting an ES5 limitation running on a modern environment.
**Note:** before MobX 6, one had to pick either MobX 4 for older engines, or MobX 5 for new engines. However, MobX 6 supports both, although polyfills for certain APIs like Map will be required when targetting older JavaScript engines.
Proxies cannot be polyfilled. Even though polyfills do exist, they don't support the full spec and are unsuitable for MobX. Don't use them.
### Limitations without Proxy support
1. Observable arrays are not real arrays, so they won't pass the `Array.isArray()` check. The practical consequence is that you often need to `.slice()` the array first (to get a shallow copy of the real array) before passing it to third party libraries. For example, concatenating observable arrays doesn't work as expected, so `.slice()` them first.
2. Adding or deleting properties of existing observable plain objects after creation is not automatically picked up. If you intend to use objects as index based lookup maps, in other words, as dynamic collections of things, use observable Maps instead.
It is possible to dynamically add properties to objects, and detect their additions, even when Proxies aren't enabled.
This can be achieved by using the [Collection utilities {🚀}](collection-utilities.md). Make sure that (new) properties are set using the `set` utility, and that the objects are iterated using one of the `values` / `keys` or `entries` utilities, rather than the built-in JavaScript mechanisms.
But, since this is really easy to forget, we instead recommend using observable Maps if possible.
## Decorator support
For enabling experimental decorator support check out the [Enabling decorators {🚀}](enabling-decorators.md) section.
## Linting options
To help you adopt the patterns advocated by MobX, a strict separation between actions, state and derivations, MobX can _"lint"_ your coding patterns at runtime by hinting at smells. To make sure MobX is as strict as possible, adopt the following settings and read on for their explanations:
```typescript
import { configure } from "mobx"
configure({
enforceActions: "always",
computedRequiresReaction: true,
reactionRequiresObservable: true,
observableRequiresReaction: true,
disableErrorBoundaries: true
})
```
At some point you will discover that this level of strictness can be pretty annoying.
It is fine to disable these rules to gain productivity once you are sure you (and your colleagues) grokked the mental model of MobX.
Also, occasionally you will have a case where you have to suppress the warnings triggered by these rules (for example by wrapping in `runInAction`).
That is fine, there are good exceptions to these recommendations.
Don't be fundamentalist about them.
Make sure to also try our [`eslint` plugin](https://github.com/mobxjs/mobx/blob/main/packages/eslint-plugin-mobx/README.md).
While some problems are discoverable statically, others are detectable only at runtime.
The plugin is intended to complement these rules, not to replace them.
The autofix feature can also help with the boilerplate code.
#### `enforceActions`
The goal of _enforceActions_ is that you don't forget to wrap event handlers in [`action`](actions.md).
Possible options:
- `"observed"` (**default**): All state that is observed _somewhere_ needs to be changed through actions. This is the default, and the recommended strictness mode in non-trivial applications.
- `"never"`: State can be changed from anywhere.
- `"always"`: State always needs to be changed through actions, which in practice also includes creation.
The benefit of `"observed"` is that it allows you to create observables outside of actions and modify them freely, as long as they aren't used anywhere yet.
Since state should in principle always be created from some event handlers, and event handlers should be wrapped, `"always"` captures this the best. But you probably don't want to use this mode in unit tests.
In the rare case where you create observables lazily, for example in a computed property, you can wrap the creation ad-hoc in an action using `runInAction`.
#### `computedRequiresReaction: boolean`
Forbids the direct access of any unobserved computed value from outside an action or reaction.
This guarantees you aren't using computed values in a way where MobX won't cache them. **Default: `false`**.
In the following example, MobX won't cache the computed value in the first code block, but will cache the result in the second and third block:
```javascript
class Clock {
seconds = 0
get milliseconds() {
console.log("computing")
return this.seconds * 1000
}
constructor() {
makeAutoObservable(this)
}
}
const clock = new Clock()
{
// This would compute twice, but is warned against by this flag.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
}
{
runInAction(() => {
// Will compute only once.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
})
}
{
autorun(() => {
// Will compute only once.
console.log(clock.milliseconds)
console.log(clock.milliseconds)
})
}
```
#### `observableRequiresReaction: boolean`
Warns about any unobserved observable access.
Use this if you want to check whether you are using observables without a "MobX context".
This is a great way to find any missing `observer` wrappers, for example in React components. But it will find missing actions as well. **Default: `false`**
```javascript
configure({ observableRequiresReaction: true })
```
**Note:** using propTypes on components that are wrapped with `observer` might trigger false positives for this rule.
#### `reactionRequiresObservable: boolean`
Warns when a reaction (e.g. `autorun`) is created without accessing any observables.
Use this to check whether you are unnecessarily wrapping React components with `observer`, wrapping functions with `action`, or find cases where you simply forgot to make some data structures or properties observable. **Default: `false`**
```javascript
configure({ reactionRequiresObservable: true })
```
#### `disableErrorBoundaries: boolean`
By default, MobX will catch and re-throw exceptions happening in your code to make sure that a reaction in one exception does not prevent the scheduled execution of other, possibly unrelated, reactions. This means exceptions are not propagated back to the original causing code and therefore you won't be able to catch them using try/catch.
By disabling error boundaries, exceptions can escape derivations. This might ease debugging, but might leave MobX and by extension your application in an unrecoverable broken state. **Default: `false`**.
This option is great for unit tests, but remember to call `_resetGlobalState` after each test, for example by using `afterEach` in jest, for example:
```js
import { _resetGlobalState, observable, autorun, configure } from "mobx"
configure({ disableErrorBoundaries: true })
test("Throw if age is negative", () => {
expect(() => {
const age = observable.box(10)
autorun(() => {
if (age.get() < 0) throw new Error("Age should not be negative")
})
age.set(-1)
}).toThrow("Age should not be negative")
})
afterEach(() => {
_resetGlobalState()
})
```
#### `safeDescriptors: boolean`
MobX makes some fields **non-configurable** or **non-writable** to prevent you from doing things that are not supported or would most likely break your code. However this can also prevent **spying/mocking/stubbing** in your tests.
`configure({ safeDescriptors: false })` disables this safety measure, making everything **configurable** and **writable**.
Note it doesn't affect existing observables, only the ones created after it's been configured.
**Use with caution** and only when needed - do not turn this off globally for all tests, otherwise you risk false positives (passing tests with broken code). **Default: `true`**
```javascript
configure({ safeDescriptors: false })
```
## Further configuration options
#### `isolateGlobalState: boolean`
Isolates the global state of MobX when there are multiple instances of MobX active in the same environment. This is useful when you have an encapsulated library that is using MobX, living in the same page as the app that is using MobX. The reactivity inside the library will remain self-contained when you call `configure({ isolateGlobalState: true })` from it.
Without this option, if multiple MobX instances are active, their internal state will be shared. The benefit is that observables from both instances work together, the downside is that the MobX versions have to match. **Default: `false`**
```javascript
configure({ isolateGlobalState: true })
```
#### `reactionScheduler: (f: () => void) => void`
Sets a new function that executes all MobX reactions.
By default `reactionScheduler` just runs the `f` reaction without any other behavior.
This can be useful for basic debugging, or slowing down reactions to visualize application updates. **Default: `f => f()`**
```javascript
configure({
reactionScheduler: (f): void => {
console.log("Running an event after a delay:", f)
setTimeout(f, 100)
}
})
```
---
---
title: Creating custom observables
sidebar_label: Custom observables {🚀}
hide_title: true
---
# Creating custom observables {🚀}
At some point you might want to have more data structures or other things (like streams) that can be used in reactive computations.
Achieving this is pretty simple by using **atoms**, which is the class that MobX uses internally for all observable data types.
Atoms can be used to signal to MobX that some observable data source has been observed or changed, and MobX will let the atom know when it's being used and when it's not.
> _**Tip**: In many cases you can avoid the need to create your own atoms just by creating a normal observable, and using
the [`onBecomeObserved`](lazy-observables.md) utility to be notified when MobX starts tracking it._
The following example demonstrates how you can create an observable `Clock` that returns the current date-time, which can then be used in reactive functions.
This clock will only actually tick if it is being observed by someone.
The complete API of the `Atom` class is demonstrated by this example. For further information, see [`createAtom`](api.md#createAtom).
```javascript
import { createAtom, autorun } from "mobx"
class Clock {
atom
intervalHandler = null
currentDateTime
constructor() {
// Creates an atom to interact with the MobX core algorithm.
this.atom = createAtom(
// 1st parameter:
// - Atom's name, for debugging purposes.
"Clock",
// 2nd (optional) parameter:
// - Callback for when this atom transitions from unobserved to observed.
() => this.startTicking(),
// 3rd (optional) parameter:
// - Callback for when this atom transitions from observed to unobserved.
() => this.stopTicking()
// The same atom transitions between these two states multiple times.
)
}
getTime() {
// Let MobX know this observable data source has been used.
//
// reportObserved will return true if the atom is currently being observed
// by some reaction. If needed, it will also trigger the startTicking
// onBecomeObserved event handler.
if (this.atom.reportObserved()) {
return this.currentDateTime
} else {
// getTime was called, but not while a reaction was running, hence
// nobody depends on this value, and the startTicking onBecomeObserved
// handler won't be fired.
//
// Depending on the nature of your atom it might behave differently
// in such circumstances, like throwing an error, returning a default
// value, etc.
return new Date()
}
}
tick() {
this.currentDateTime = new Date()
this.atom.reportChanged() // Let MobX know that this data source has changed.
}
startTicking() {
this.tick() // Initial tick.
this.intervalHandler = setInterval(() => this.tick(), 1000)
}
stopTicking() {
clearInterval(this.intervalHandler)
this.intervalHandler = null
}
}
const clock = new Clock()
const disposer = autorun(() => console.log(clock.getTime()))
// Prints the time every second.
// Stop printing. If nobody else uses the same `clock`, it will stop ticking as well.
disposer()
```
---
---
title: Defining data stores
sidebar_label: Defining data stores
hide_title: true
---
# Defining data stores
This section contains some of the best practices for building large scale maintainable projects we discovered at Mendix while working with MobX.
This section is opinionated and you are in no way forced to apply these practices.
There are many ways of working with MobX and React, and this is just one of them.
This section focuses on an unobtrusive way of working with MobX, which works well in existing codebases, or with classic MVC patterns. Alternative, more opinionated ways of organizing stores are [mobx-state-tree](https://github.com/mobxjs/mobx-state-tree) and [mobx-keystone](https://mobx-keystone.js.org/). Both ship with cool features such as structurally shared snapshots, action middlewares, JSON patch support etc. out of the box.
## Stores
Stores can be found in any Flux architecture and can be compared a bit with controllers in the MVC pattern.
The main responsibility of stores is to move _logic_ and _state_ out of your components into a standalone testable unit that can be used in both frontend and backend JavaScript.
Most applications benefit from having at least two stores: one for the _domain state_ and another one for the _UI state_. The advantage of separating those two is you can reuse and test _domain state_ universally, and you might very well reuse it in other applications.
## Domain Stores
Your application will contain one or multiple _domain_ stores.
These stores store the data your application is all about.
Todo items, users, books, movies, orders, you name it.
Your application will most probably have at least one domain store.
A single domain store should be responsible for a single concept in your application. A single store is often organized as a tree structure with
multiple domain objects inside.
For example: one domain store for your products, and one for your orders and orderlines.
As a rule of thumb: if the nature of the relationship between two items is containment, they should typically be in the same store.
So a store just manages _domain objects_.
These are the responsibilities of a store:
- Instantiate domain objects. Make sure domain objects know the store they belong to.
- Make sure there is only one instance of each of your domain objects.
The same user, order or todo should not be stored twice in memory.
This way you can safely use references and also be sure you are looking at the latest instance, without ever having to resolve a reference.
This is fast, straightforward and convenient when debugging.
- Provide backend integration. Store data when needed.
- Update existing instances if updates are received from the backend.
- Provide a standalone, universal, testable component of your application.
- To make sure your store is testable and can be run server-side, you will probably move doing actual websocket / http requests to a separate object so that you can abstract over your communication layer.
- There should be only one instance of a store.
### Domain objects
Each domain object should be expressed using its own class (or constructor function).
There is no need to treat your client-side application state as some kind of database.
Real references, cyclic data structures and instance methods are powerful concepts in JavaScript.
Domain objects are allowed to refer directly to domain objects from other stores.
Remember: we want to keep our actions and views as simple as possible and needing to manage references and doing garbage collection yourself might be a step backward.
Unlike many Flux architectures such as Redux, with MobX there is no need to normalize your data, and this makes it a lot simpler to build the _essentially_ complex parts of your application:
your business rules, actions and user interface.
Domain objects can delegate all their logic to the store they belong to if that suits your application well.
It is possible to express your domain objects as plain objects, but classes have some important advantages over plain objects:
- They can have methods.
This makes your domain concepts easier to use standalone and reduces the amount of contextual awareness that is needed in your application.
Just pass objects around.
You don't have to pass stores around, or have to figure out which actions can be applied to an object if they are just available as instance methods.
This is especially important in large applications.
- They offer fine grained control over the visibility of attributes and methods.
- Objects created using a constructor function can freely mix observable properties and methods, and non-observable properties and methods.
- They are easily recognizable and can be strictly type-checked.
### Example domain store
```javascript
import { makeAutoObservable, runInAction, reaction } from "mobx"
import uuid from "node-uuid"
export class TodoStore {
authorStore
transportLayer
todos = []
isLoading = true
constructor(transportLayer, authorStore) {
makeAutoObservable(this)
this.authorStore = authorStore // Store that can resolve authors.
this.transportLayer = transportLayer // Thing that can make server requests.
this.transportLayer.onReceiveTodoUpdate(updatedTodo =>
this.updateTodoFromServer(updatedTodo)
)
this.loadTodos()
}
// Fetches all Todos from the server.
loadTodos() {
this.isLoading = true
this.transportLayer.fetchTodos().then(fetchedTodos => {
runInAction(() => {
fetchedTodos.forEach(json => this.updateTodoFromServer(json))
this.isLoading = false
})
})
}
// Update a Todo with information from the server. Guarantees a Todo only
// exists once. Might either construct a new Todo, update an existing one,
// or remove a Todo if it has been deleted on the server.
updateTodoFromServer(json) {
let todo = this.todos.find(todo => todo.id === json.id)
if (!todo) {
todo = new Todo(this, json.id)
this.todos.push(todo)
}
if (json.isDeleted) {
this.removeTodo(todo)
} else {
todo.updateFromJson(json)
}
}
// Creates a fresh Todo on the client and the server.
createTodo() {
const todo = new Todo(this)
this.todos.push(todo)
return todo
}
// A Todo was somehow deleted, clean it from the client memory.
removeTodo(todo) {
this.todos.splice(this.todos.indexOf(todo), 1)
todo.dispose()
}
}
// Domain object Todo.
export class Todo {
id = null // Unique id of this Todo, immutable.
completed = false
task = ""
author = null // Reference to an Author object (from the authorStore).
store = null
autoSave = true // Indicator for submitting changes in this Todo to the server.
saveHandler = null // Disposer of the side effect auto-saving this Todo (dispose).
constructor(store, id = uuid.v4()) {
makeAutoObservable(this, {
id: false,
store: false,
autoSave: false,
saveHandler: false,
dispose: false
})
this.store = store
this.id = id
this.saveHandler = reaction(
() => this.asJson, // Observe everything that is used in the JSON.
json => {
// If autoSave is true, send JSON to the server.
if (this.autoSave) {
this.store.transportLayer.saveTodo(json)
}
}
)
}
// Remove this Todo from the client and the server.
delete() {
this.store.transportLayer.deleteTodo(this.id)
this.store.removeTodo(this)
}
get asJson() {
return {
id: this.id,
completed: this.completed,
task: this.task,
authorId: this.author ? this.author.id : null
}
}
// Update this Todo with information from the server.
updateFromJson(json) {
this.autoSave = false // Prevent sending of our changes back to the server.
this.completed = json.completed
this.task = json.task
this.author = this.store.authorStore.resolveAuthor(json.authorId)
this.autoSave = true
}
// Clean up the observer.
dispose() {
this.saveHandler()
}
}
```
## UI stores
The _ui-state-store_ is often very specific for your application, but usually very simple as well.
This store typically doesn't have much logic in it, but will store a plethora of loosely coupled pieces of information about the UI.
This is ideal as most applications will change the UI state often during the development process.
Things you will typically find in UI stores:
- Session information
- Information about how far your application has loaded
- Information that will not be stored in the backend
- Information that affects the UI globally
- Window dimensions
- Accessibility information
- Current language
- Currently active theme
- User interface state as soon as it affects multiple, further unrelated components:
- Current selection
- Visibility of toolbars, etc.
- State of a wizard
- State of a global overlay
It might very well be that these pieces of information start as internal state of a specific component (for example the visibility of a toolbar), but after a while you discover that you need this information somewhere else in your application.
Instead of pushing state in such a case upwards in the component tree, like you would do in plain React apps, you just move that state to the _ui-state-store_.
For isomorphic applications you might also want to provide a stub implementation of this store with sane defaults so that all components render as expected.
You might distribute the _ui-state-store_ through your application by passing it as React context.
Example of a store (using ES6 syntax):
```javascript
import { makeAutoObservable, observable, computed } from "mobx"
export class UiState {
language = "en_US"
pendingRequestCount = 0
// .struct makes sure observer won't be signaled unless the
// dimensions object changed in a deepEqual manner.
windowDimensions = {
width: window.innerWidth,
height: window.innerHeight
}
constructor() {
makeAutoObservable(this, { windowDimensions: observable.struct })
window.onresize = () => {
this.windowDimensions = getWindowDimensions()
}
}
get appIsInSync() {
return this.pendingRequestCount === 0
}
}
```
## Combining multiple stores
An often asked question is how to combine multiple stores without using singletons. How will they know about each other?
An effective pattern is to create a `RootStore` that instantiates all stores, and share references. The advantage of this pattern is:
1. Simple to set up.
2. Supports strong typing well.
3. Makes complex unit tests easy as you just have to instantiate a root store.
Example:
```javascript
class RootStore {
constructor() {
this.userStore = new UserStore(this)
this.todoStore = new TodoStore(this)
}
}
class UserStore {
constructor(rootStore) {
this.rootStore = rootStore
}
getTodos(user) {
// Access todoStore through the root store.
return this.rootStore.todoStore.todos.filter(todo => todo.author === user)
}
}
class TodoStore {
todos = []
rootStore
constructor(rootStore) {
makeAutoObservable(this)
this.rootStore = rootStore
}
}
```
When using React, this root store is typically inserted into the component tree by using React context.
---
---
title: Decorators
sidebar_label: Decorators {🚀}
hide_title: true
---
# Decorators
## Enabling decorators
After years of alterations, ES decorators have finally reached Stage 3 in the TC39 process, meaning that they are quite stable and won't undergo breaking changes again like the previous decorator proposals have. MobX has implemented support for this new "2022.3/Stage 3" decorator syntax.
With modern decorators, it is no longer needed to call `makeObservable` / `makeAutoObservable`.
2022.3 Decorators are supported in:
- TypeScript (5.0 and higher, make sure that the `experimentalDecorators` flag is NOT enabled). [Example commit](https://github.com/mweststrate/currencies-demo/commit/acb9ac8c148e8beef88042c847bb395131e85d60).
- For Babel make sure the plugin [`proposal-decorators`](https://babeljs.io/docs/babel-plugin-proposal-decorators) is enabled with the highest version (currently `2023-05`). [Example commit](https://github.com/mweststrate/currencies-demo/commit/4999d2228208f3e1e10bc00a272046eaefde8585).
```js
// tsconfig.json
{
"compilerOptions": {
"experimentalDecorators": false /* or just remove the flag */
}
}
// babel.config.json (or equivalent)
{
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"version": "2023-05"
}
]
]
}
```
- Vite configuration
```js
// vite.config.js
{
plugins: [
react({
babel: {
plugins: [
[
"@babel/plugin-proposal-decorators",
{
version: "2023-05"
}
]
]
}
})
]
}
```
## Using decorators
```javascript
import { observable, computed, action } from "mobx"
class Todo {
id = Math.random()
@observable accessor title = ""
@observable accessor finished = false
@action
toggle() {
this.finished = !this.finished
}
}
class TodoList {
@observable accessor todos = []
@computed
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
}
```
Notice the usage of the new `accessor` keyword when using `@observable`.
It is part of the 2022.3 spec and is required if you want to use modern decorators.
Using legacy decorators
We do not recommend codebases to use TypeScript / Babel legacy decorators since they well never become an official part of the language, but you can still use them. It does require a specific setup for transpilation:
MobX before version 6 encouraged the use of legacy decorators and mark things as `observable`, `computed` and `action`.
While MobX 6 recommends against using these decorators (and instead use either modern decorators or [`makeObservable` / `makeAutoObservable`](observable-state.md)), it is in the current major version still possible.
Support for legacy decorators will be removed in MobX 7.
```javascript
import { makeObservable, observable, computed, action } from "mobx"
class Todo {
id = Math.random()
@observable title = ""
@observable finished = false
constructor() {
makeObservable(this)
}
@action
toggle() {
this.finished = !this.finished
}
}
class TodoList {
@observable todos = []
@computed
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor() {
makeObservable(this)
}
}
```
Migrating from legacy decorators
To migrate from legacy decorators to modern decorators, perform the following steps:
1. Disable / remove the `experimentalDecorators` flag from your TypeScript configuration (or Babel equivalent)
2. Remove all `makeObservable(this)` calls from class constructors that use decorators.
3. Replace all instances of `@observable` (and variations) with `@observable accessor`
Please note that adding `accessor` to a class property will change it into `get` and `set` class methods. Unlike class properties, class methods are not enumerable. This may introduce new behavior with some APIs, such as `Object.keys`, `JSON.stringify`, etc.
Decorator changes / gotchas
MobX' 2022.3 Decorators are very similar to the MobX 5 decorators, so usage is mostly the same, but there are some gotchas:
- `@observable accessor` decorators are _not_ enumerable. `accessor`s do not have a direct equivalent in the past - they're a new concept in the language. We've chosen to make them non-enumerable, non-own properties in order to better follow the spirit of the ES language and what `accessor` means.
The main cases for enumerability seem to have been around serialization and rest destructuring.
- Regarding serialization, implicitly serializing all properties probably isn't ideal in an OOP-world anyway, so this doesn't seem like a substantial issue (consider implementing `toJSON` or using `serializr` as possible alternatives)
- Addressing rest-destructuring, such is an anti-pattern in MobX - doing so would (likely unwantedly) touch all observables and make the observer overly-reactive).
- `@action some_field = () => {}` was and is valid usage. However, inheritance is different between legacy decorators and modern decorators.
- In legacy decorators, if superclass has a field decorated by `@action`, and subclass tries to override the same field, it will throw a `TypeError: Cannot redefine property`.
- In modern decorators, if superclass has a field decorated by `@action`, and subclass tries to override the same field, it's allowed to override the field. However, the field on subclass is not an action unless it's also decorated with `@action` in subclass declaration.
## Using `observer` as a decorator
The `observer` function from `mobx-react` is both a function and a decorator that can be used on class components:
```javascript
@observer
class Timer extends React.Component {
/* ... */
}
```
---
---
title: Migrating from MobX 4/5
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../migrating-from-4-or-5.md)
---
---
title: Installation
sidebar_label: Installation
hide_title: true
---
# Installation
MobX works in any ES5 environment, which includes browsers and NodeJS.
There are three types of React bindings:
- [mobx-react-lite](https://github.com/mobxjs/mobx/tree/main/packages/mobx-react-lite). Utilities to manually apply observation
- [mobx-react-observer](https://github.com/christianalfoni/mobx-react-observer). Babel/swc plugin to automatically apply observation to components
- [mobx-react](https://github.com/mobxjs/mobx/tree/main/packages/mobx-react). Support for class components
Append the appropriate bindings for your use case to the _Yarn_ or _NPM_ command below:
**Yarn:** `yarn add mobx`
**NPM:** `npm install --save mobx`
**CDN:** https://cdnjs.com/libraries/mobx / https://unpkg.com/mobx/dist/mobx.umd.production.min.js
# Transpilation settings
## MobX and Decorators
Based on your preference, MobX can be used with or without decorators.
Both the legacy implementation and the standardised TC-39 version of decorators are currently supported.
See [enabling-decorators](enabling-decorators.md) for more details on how to enable them.
Legacy decorator support will be removed in MobX 7, in favor of the standard.
## Use spec compliant transpilation for class properties
When using MobX with TypeScript or Babel, and you plan to use classes; make sure to update your configuration to use a TC-39 spec compliant transpilation for class fields, since this is not always the default. Without this, class fields cannot be made observable before they are initialized.
- **TypeScript**: Set the compiler option `"useDefineForClassFields": true`.
- **Babel**: Make sure to use at least version 7.12, with the following configuration:
```json
{
// Babel < 7.13.0
"plugins": [["@babel/plugin-proposal-class-properties", { "loose": false }]],
// Babel >= 7.13.0 (https://babeljs.io/docs/en/assumptions)
"plugins": [["@babel/plugin-proposal-class-properties"]],
"assumptions": {
"setPublicClassFields": false
}
}
```
For verification insert this piece of code at the beginning of your sources (eg. `index.js`)
```javascript
if (!new class { x }().hasOwnProperty('x')) throw new Error('Transpiler is not configured correctly');
```
## MobX on older JavaScript environments
By default, MobX uses proxies for optimal performance and compatibility. However, on older JavaScript engines `Proxy` is not available (check out [Proxy support](https://compat-table.github.io/compat-table/es6/#test-Proxy)). Examples of such are Internet Explorer (before Edge), Node.js < 6, iOS < 10, Android before RN 0.59.
In such cases, MobX can fallback to an ES5 compatible implementation which works almost identically, although there are a few [limitations without Proxy support](configuration.md#limitations-without-proxy-support). You will have to explicitly enable the fallback implementation by configuring [`useProxies`](configuration.md#proxy-support):
```javascript
import { configure } from "mobx"
configure({ useProxies: "never" }) // Or "ifavailable".
```
This option will be removed in MobX 7.
## MobX on other frameworks / platforms
- [MobX.dart](https://mobx.netlify.app/): MobX for Flutter / Dart
- [lit-mobx](https://github.com/adobe/lit-mobx): MobX for lit-element
- [mobx-angular](https://github.com/mobxjs/mobx-angular): MobX for angular
- [mobx-vue](https://github.com/mobxjs/mobx-vue): MobX for Vue
---
---
title: Intercept & Observe
sidebar_label: Intercept & Observe {🚀}
hide_title: true
---
# Intercept & Observe {🚀}
_⚠️ **Warning**: intercept and observe are low level utilities, and should not be needed in practice. Use some form of [reaction](reactions.md) instead, as `observe` doesn't respect transactions and doesn't support deep observing of changes. Using these utilities is an anti-pattern. If you intend to get access to the old and new value using `observe`, use [`reaction`](reactions.md#reaction) instead. ⚠️_
`observe` and `intercept` can be used to monitor the changes of a single observable, but they **_don't_** track nested observables.
- `intercept` can be used to detect and modify mutations before they are applied to the observable (validating, normalizing or cancelling).
- `observe` allows you to intercept changes after they have been made.
## Intercept
Usage: `intercept(target, propertyName?, interceptor)`
_Please avoid this API. It basically provides a bit of aspect-oriented programming, creating flows that are really hard to debug. Instead, do things like data validation **before** updating any state, rather than during._
- `target`: the observable to guard.
- `propertyName`: optional parameter to specify a specific property to intercept. Note that `intercept(user.name, interceptor)` is fundamentally different from `intercept(user, "name", interceptor)`. The first tries to add an interceptor to the _current_ `value` inside `user.name`, which might not be an observable at all. The latter intercepts changes to the `name` _property_ of `user`.
- `interceptor`: callback that is invoked for _each_ change that is made to the observable. Receives a single change object describing the mutation.
The `intercept` should tell MobX what needs to happen with the current change.
Therefore it should do one of the following things:
1. Return the received `change` object as-is from the function, in which case the mutation will be applied.
2. Modify the `change` object and return it, for example to normalize the data. Not all fields are modifiable, see below.
3. Return `null`, this indicates that the change can be ignored and shouldn't be applied. This is a powerful concept with which you can for example make your objects temporarily immutable.
4. Throw an exception, if for example some invariant isn't met.
The function returns a `disposer` function that can be used to cancel the interceptor when invoked.
It is possible to register multiple interceptors to the same observable.
They will be chained in registration order.
If one of the interceptors returns `null` or throws an exception, the other interceptors won't be evaluated anymore.
It is also possible to register an interceptor both on a parent object and on an individual property.
In that case the parent object interceptors are run before the property interceptors.
```javascript
const theme = observable({
backgroundColor: "#ffffff"
})
const disposer = intercept(theme, "backgroundColor", change => {
if (!change.newValue) {
// Ignore attempts to unset the background color.
return null
}
if (change.newValue.length === 6) {
// Correct missing '#' prefix.
change.newValue = "#" + change.newValue
return change
}
if (change.newValue.length === 7) {
// This must be a properly formatted color code!
return change
}
if (change.newValue.length > 10) {
// Stop intercepting future changes.
disposer()
}
throw new Error("This doesn't look like a color at all: " + change.newValue)
})
```
## Observe
Usage: `observe(target, propertyName?, listener, invokeImmediately?)`
_See above notice, please avoid this API and use [`reaction`](reactions.md#reaction) instead._
- `target`: the observable to observe.
- `propertyName`: optional parameter to specify a specific property to observe. Note that `observe(user.name, listener)` is fundamentally different from `observe(user, "name", listener)`. The first observes the _current_ `value` inside `user.name`, which might not be an observable at all. The latter observes the `name` _property_ of `user`.
- `listener`: callback that will be invoked for _each_ change that is made to the observable. Receives a single change object describing the mutation, except for boxed observables, which will invoke the `listener` with two parameters: `newValue, oldValue`.
- `invokeImmediately`: _false_ by default. Set it to _true_ if you want `observe` to invoke the `listener` directly with the state of the observable, instead of waiting for the first change. Not supported (yet) by all kinds of observables.
The function returns a `disposer` function that can be used to cancel the observer.
Note that `transaction` does not affect the working of the `observe` method(s).
This means that even inside a transaction `observe` will fire its listeners for each mutation.
Hence [`autorun`](reactions.md#autorun) is usually a more powerful and declarative alternative to `observe`.
_`observe` reacts to **mutations** when they are being made, while reactions like `autorun` or `reaction` react to **new values** when they become available. In many cases the latter is sufficient._
Example:
```javascript
import { observable, observe } from "mobx"
const person = observable({
firstName: "Maarten",
lastName: "Luther"
})
// Observe all fields.
const disposer = observe(person, change => {
console.log(change.type, change.name, "from", change.oldValue, "to", change.object[change.name])
})
person.firstName = "Martin"
// Prints: 'update firstName from Maarten to Martin'
// Ignore any future updates.
disposer()
// Observe a single field.
const disposer2 = observe(person, "lastName", change => {
console.log("LastName changed to ", change.newValue)
})
```
Related blog: [Object.observe is dead. Long live mobx.observe](https://medium.com/@mweststrate/object-observe-is-dead-long-live-mobservable-observe-ad96930140c5)
## Event overview
The callbacks of `intercept` and `observe` will receive an event object which has at least the following properties:
- `object`: the observable triggering the event.
- `debugObjectName`: the name of the observable triggering the event (for debugging).
- `observableKind`: the type of the observable (value, set, array, object, map, computed).
- `type` (string): the type of the current event.
These are the additional fields that are available per type:
| Observable type | Event type | Property | Description | Available during intercept | Can be modified by intercept |
| ---------------------------- | ---------- | ------------ | ------------------------------------------------------------------------------------------------- | -------------------------- | ---------------------------- |
| Object | add | name | Name of the property being added. | √ | |
| | | newValue | The new value being assigned. | √ | √ |
| | update\* | name | Name of the property being updated. | √ | |
| | | newValue | The new value being assigned. | √ | √ |
| | | oldValue | The value that is replaced. | | |
| Array | splice | index | Starting index of the splice. Splices are also fired by `push`, `unshift`, `replace`, etc. | √ | |
| | | removedCount | Amount of items being removed. | √ | √ |
| | | added | Array with items being added. | √ | √ |
| | | removed | Array with items that were removed. | | |
| | | addedCount | Amount of items that were added. | | |
| | update | index | Index of the single entry being updated. | √ | |
| | | newValue | The newValue that is / will be assigned. | √ | √ |
| | | oldValue | The old value that was replaced. | | |
| Map | add | name | The name of the entry that was added. | √ | |
| | | newValue | The new value that is being assigned. | √ | √ |
| | update | name | The name of the entry being updated. | √ | |
| | | newValue | The new value that is being assigned. | √ | √ |
| | | oldValue | The value that has been replaced. | | |
| | delete | name | The name of the entry being removed. | √ | |
| | | oldValue | The value of the entry that was removed. | | |
| Boxed & computed observables | create | newValue | The value that was assigned during creation. Only available as `spy` event for boxed observables. | | |
| | update | newValue | The new value being assigned. | √ | √ |
| | | oldValue | The previous value of the observable. | | |
**Note:** object `update` events won't fire for updated computed values (as those aren't mutations). But it is possible to observe them by explicitly subscribing to the specific property using `observe(object, 'computedPropertyName', listener)`.
---
---
title: The gist of MobX
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../the-gist-of-mobx.md)
---
---
title: About this documentation
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../about-this-documentation.md)
---
---
title: Installation
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../installation.md)
---
---
title: Creating lazy observables
sidebar_label: Lazy observables {🚀}
hide_title: true
---
# Creating lazy observables {🚀}
Usage:
- `onBecomeObserved(observable, property?, listener: () => void): (() => void)`
- `onBecomeUnobserved(observable, property?, listener: () => void): (() => void)`
Functions `onBecomeObserved` and `onBecomeUnobserved` can be used to attach lazy behavior or side effects to existing observables. They hook into the observability system of MobX and get notified when an observable _starts_ and _stops_ becoming observed. They both return a _disposer_ function that detaches the _listener_.
In the example below we use them to perform network fetches only when the observed value is actually in use.
```javascript
export class City {
location
temperature
interval
constructor(location) {
makeAutoObservable(this, {
resume: false,
suspend: false
})
this.location = location
// Only start data fetching if temperature is actually used!
onBecomeObserved(this, "temperature", this.resume)
onBecomeUnobserved(this, "temperature", this.suspend)
}
resume = () => {
log(`Resuming ${this.location}`)
this.interval = setInterval(() => this.fetchTemperature(), 5000)
}
suspend = () => {
log(`Suspending ${this.location}`)
this.temperature = undefined
clearInterval(this.interval)
}
fetchTemperature = flow(function* () {
// Data fetching logic...
})
}
```
---
---
title: Migrating from MobX 4/5
sidebar_label: Migrating from MobX 4/5 {🚀}
hide_title: true
---
# Migrating from MobX 4/5 {🚀}
MobX 6 is quite different from MobX 5. This pages covers a migration guide from MobX 4 and 5 to 6, and an extensive list of all the changes.
For a better understanding, check out the MobX 6.0 [CHANGELOG](https://github.com/mobxjs/mobx/blob/main/packages/mobx/CHANGELOG.md#600).
_⚠️ **Warning**: Depending on factors like the size and complexity of your code base, your MobX usage patterns, and the quality of your automated tests, this migration guide might take you anywhere between an hour and a couple of days. Please refrain from upgrading if you don't trust your Continuous Integration or QA / test procedures enough to pick up any unexpected breakages. Unexpected behavioral changes might be caused by changes in MobX itself or the changes needed to your Babel / TypeScript build configuration. ⚠️_
## Getting started
1. Update `mobx` to the latest version of MobX 4/5 and solve any deprecation messages.
2. Update `mobx` to version 6.
3. If you are upgrading from MobX 4, and you will need to support Internet Explorer / React Native without proxies, call `import { configure } from "mobx"; configure({ useProxies: "never" })` at the initialization of your application, to back-out of the Proxy implementation. Check out the [Proxy Support](configuration.md#proxy-support) section for more details.
4. For babel users:
- If you are using Babel and have class-properties enabled, disable the legacy loose field support: `["@babel/plugin-proposal-class-properties", { "loose": false }]`
- (Optional) In MobX 6 decorators have become opt-in. If you no longer wish to use decorators, remove `plugin-proposal-decorators` from your babel configuration and dependencies. Check out the [Enabling decorators {🚀}](enabling-decorators.md) section for more details.
5. For Typescript users:
- Add the flag `"useDefineForClassFields": true` to your compiler config.
- (Optional) In MobX 6 decorators have become opt-in. If you no longer wish to use decorators, remove / disable the `experimentalDecorators` configuration from your TypeScript config. Check out the [Enabling decorators {🚀}](enabling-decorators.md) section for more details.
6. The MobX default configuration has become more strict. We recommend to adopt the new defaults after completing the upgrade, check out the [Configuration {🚀}](configuration.md) section. During migration, we recommend to configure MobX in the same way as it would be in v4/v5 out of the box: `import {configure} from "mobx"; configure({ enforceActions: "never" });`. After finishing the entire migration process and validating that your project works as expected, consider enabling the flags `computedRequiresReaction`, `reactionRequiresObservable` and `observableRequiresReaction` and `enforceActions: "observed"` to write more idiomatic MobX code.
## Upgrading classes to use `makeObservable`
Due to standardized JavaScript limitations in how class fields are constructed, it is no longer possible for MobX to alter the behavior of class fields by means of decorators or the `decorate` utility. Instead, fields have to be made observable by the `constructor`. This can be done in three different ways:
1. Remove all decorators and call `makeObservable` in the `constructor` and explicitly define which field should be made observable using which decorator. For example: `makeObservable(this, { count: observable, tick: action, elapsedTime: computed })` (note that the second argument corresponds to what would be passed to `decorate`). This is the recommended approach if you want to drop decorators in your code base, and the project isn't yet too big.
2. Leave all the decorators and call `makeObservable(this)` in the `constructor`. This will pick up the metadata generated by the decorators. This is the recommended way if you want to limit the impact of a MobX 6 migration.
3. Remove decorators and use `makeAutoObservable(this)` in the class `constructor`'s.
Check out [makeObservable / makeAutoObservable](observable-state.md) for more details.
Some specifics to note:
1. Using `makeObservable` / `makeAutoObservable` needs to be done in every class definition that declares MobX based members. So if a sub-class and super-class both introduce observable members, they will both have to call `makeObservable`.
2. `makeAutoObservable` will mark methods using a new decorator [`autoAction`](observable-state.md#autoAction), that will apply `action` only if it is not in a derivation context. This makes it safe to call automatically decorated methods also from computed properties.
Migrating a large code base with lots of classes might be daunting. But no worries, there is a code-mod available that will automate the above process!!
## Upgrading your code with the `mobx-undecorate` codemod
If you are an existing MobX user you have code that uses a lot of decorators, or the equivalent calls to `decorate`.
The [`mobx-undecorate`](https://www.npmjs.com/package/mobx-undecorate) package provides a codemod that can automatically update your code to be conformant to MobX 6. There is no need to install it; instead you download and execute it using the [`npx`](https://www.npmjs.com/package/npx) tool which you do need to install if you haven't already.
To get rid of all uses of MobX decorators and replace them with the equivalent `makeObservable` calls, go to the directory that contains your source code and run:
```shell
npx mobx-undecorate
```
MobX will continue to support decorators -- so if you want to retain them
and only introduce `makeObservable(this)` where required, you can use the `--keepDecorators` option:
```shell
npx mobx-undecorate --keepDecorators
```
See [documentation](https://www.npmjs.com/package/mobx-undecorate) for more options.
### Limitations of `mobx-undecorate`
The `mobx-undecorate` command has to introduce a constructor in classes that do not yet have one. If base class of the constructor expects arguments, the codemod cannot introduce these arguments for the subclass being upgraded, and the `super` call won't pass them either. You have to fix these manually.
The tool will generate a `// TODO: [mobx-undecorate]` comment in these cases.
We do have a special case for React class components to do the right thing and
pass along `props` to the superclass.
## Functions are auto-converted
Functions that become part of a deep observable structure are automatically converted to [`autoAction`](observable-state.md#autoAction) or to [`flow`](actions.html#using-flow-instead-of-async--await-) if it's a generator function. See [inference rules](observable-state.html#makeautoobservable) for details.
This means that the original function reference is not preserved - in the same spirit as the original array/object/set/map reference is lost when converted to observable. [This can be surprising in some situations](https://github.com/mobxjs/mobx/issues/3616).
If this behavior is not desired use [`observable.shallow`](observable-state.html#available-annotations) / [`observable.ref`](observable-state.html#available-annotations) / [`false`](observable-state.html#available-annotations) / [`deep: flase`](observable-state.html#options-) to prevent the conversion process or make sure the function is already an `action` as shown in the issue.
---
---
title: MobX-utils
sidebar_label: MobX-utils {🚀}
hide_title: true
---
# MobX-utils {🚀}
[MobX-utils](https://github.com/mobxjs/mobx-utils) provides an extensive series of additional utility functions, observables and common patterns for MobX.
---
---
title: Creating observable state
sidebar_label: Observable state
hide_title: true
---
# Creating observable state
Properties, entire objects, arrays, Maps and Sets can all be made observable.
The basics of making objects observable is specifying an annotation per property using `makeObservable`.
The most important annotations are:
- [`observable`](#observable) defines a trackable field that stores the state.
- [`action`](actions.md) marks a method as an action that will modify the state.
- [`computed`](computeds.md) marks a getter that will derive new facts from the state and cache its output.
## `makeObservable`
Usage:
- `makeObservable(target, annotations?, options?)`
This function can be used to make _existing_ object properties observable. Any JavaScript object (including class instances) can be passed into `target`.
Typically `makeObservable` is used in the constructor of a class, and its first argument is `this`.
The `annotations` argument maps [annotations](#available-annotations) to each member. Only annotated members are affected.
Alternatively, decorators like `@observable` can be used on class members instead of calling `makeObservable` in the constructor.
Methods that derive information and take arguments (for example `findUsersOlderThan(age: number): User[]`) can not be annotated as `computed` – their read operations will still be tracked when they are called from a reaction, but their output won't be memoized to avoid memory leaks. To memoize such methods you can use [MobX-utils computedFn {🚀}](https://github.com/mobxjs/mobx-utils#computedfn) instead.
[Subclassing is supported with some limitations](subclassing.md) by using the `override` annotation (see the example [here](subclassing.md)).
```javascript
import { makeObservable, observable, computed, action, flow } from "mobx"
class Doubler {
value
constructor(value) {
makeObservable(this, {
value: observable,
double: computed,
increment: action,
fetch: flow
})
this.value = value
}
get double() {
return this.value * 2
}
increment() {
this.value++
}
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
```
**All annotated** fields are **non-configurable**.
**All non-observable** (stateless) fields (`action`, `flow`) are **non-writable**.
When using modern decorators, there is no need to call `makeObservable`, below is what a decorator based class looks like.
Note that the `@observable` annotation should always be used in combination with the `accessor` keyword.
```javascript
import { observable, computed, action, flow } from "mobx"
class Doubler {
@observable accessor value
constructor(value) {
this.value = value
}
@computed
get double() {
return this.value * 2
}
@action
increment() {
this.value++
}
@flow
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
```
```javascript
import { makeAutoObservable } from "mobx"
function createDoubler(value) {
return makeAutoObservable({
value,
get double() {
return this.value * 2
},
increment() {
this.value++
}
})
}
```
Note that classes can leverage `makeAutoObservable` as well.
The difference in the examples just demonstrate how MobX can be applied to different programming styles.
```javascript
import { observable } from "mobx"
const todosById = observable({
"TODO-123": {
title: "find a decent task management system",
done: false
}
})
todosById["TODO-456"] = {
title: "close all tickets older than two weeks",
done: true
}
const tags = observable(["high prio", "medium prio", "low prio"])
tags.push("prio: for fun")
```
In contrast to the first example with `makeObservable`, `observable` supports adding (and removing) _fields_ to an object.
This makes `observable` great for collections like dynamically keyed objects, arrays, Maps and Sets.
To use legacy decorators, `makeObservable(this)` should be called in the constructor to make sure decorators work.
```javascript
import { observable, computed, action, flow } from "mobx"
class Doubler {
@observable value
constructor(value) {
makeObservable(this)
this.value = value
}
@computed
get double() {
return this.value * 2
}
@action
increment() {
this.value++
}
@flow
*fetch() {
const response = yield fetch("/api/value")
this.value = response.json()
}
}
```
## `makeAutoObservable`
Usage:
- `makeAutoObservable(target, overrides?, options?)`
`makeAutoObservable` is like `makeObservable` on steroids, as it infers all the properties by default. You can however use the `overrides` parameter to override the default behavior with specific annotations —
in particular `false` can be used to exclude a property or method from being processed entirely.
Check out the code above for an example.
The `makeAutoObservable` function can be more compact and easier to maintain than using `makeObservable`, since new members don't have to be mentioned explicitly.
However, `makeAutoObservable` cannot be used on classes that have super or are [subclassed](subclassing.md).
Inference rules:
- All _own_ properties become `observable`.
- All `getters` become `computed`.
- All `setters` become `action`.
- All _functions_ become [`autoAction`](#autoAction).
- All _generator_ functions become `flow`. (Note that generator functions are not detectable in some transpiler configurations, if flow doesn't work as expected, make sure to specify `flow` explicitly.)
- Members marked with `false` in the `overrides` argument will not be annotated. For example, using it for read only fields such as identifiers.
## `observable`
Usage:
- `observable(source, overrides?, options?)`
- `@observable accessor` _(field decorator)_
The `observable` annotation can also be called as a function to make an entire object observable at once.
The `source` object will be cloned and all members will be made observable, similar to how it would be done by `makeAutoObservable`.
Likewise, an `overrides` map can be provided to specify the annotations of specific members.
Check out the above code block for an example.
The object returned by `observable` will be a Proxy, which means that properties that are added later to the object will be picked up and made observable as well (except when [proxy usage](configuration.md#proxy-support) is disabled).
The `observable` method can also be called with collections types like [arrays](api.md#observablearray), [Maps](api.md#observablemap) and [Sets](api.md#observableset). Those will be cloned as well and converted into their observable counterparts.
> Tip: as holds for JavaScript in general, don't use observable plain objects to create a keyed collection (for example to store a mapping from a user's UUID to user object), use maps instead. Object descriptors are aggressively cached by MobX, so if property names are unstable, this might result in memory leaks.
**Example:** observable array
The following example creates an observable and observes it using [`autorun`](reactions.md#autorun).
Working with Map and Set collections works similarly.
```javascript
import { observable, autorun } from "mobx"
const todos = observable([
{ title: "Spoil tea", completed: true },
{ title: "Make coffee", completed: false }
])
autorun(() => {
console.log(
"Remaining:",
todos
.filter(todo => !todo.completed)
.map(todo => todo.title)
.join(", ")
)
})
// Prints: 'Remaining: Make coffee'
todos[0].completed = false
// Prints: 'Remaining: Spoil tea, Make coffee'
todos[2] = { title: "Take a nap", completed: false }
// Prints: 'Remaining: Spoil tea, Make coffee, Take a nap'
todos.shift()
// Prints: 'Remaining: Make coffee, Take a nap'
```
Observable arrays have some additional nifty utility functions:
- `clear()` removes all current entries from the array.
- `replace(newItems)` replaces all existing entries in the array with new ones.
- `remove(value)` removes a single item by value from the array. Returns `true` if the item was found and removed.
**Note:** primitives and class instances are never converted to observables
Primitive values cannot be made observable by MobX since they are immutable in JavaScript (but they can be [boxed](api.md#observablebox)).
Although there is typically no use for this mechanism outside libraries.
Class instances will never be made observable automatically by passing them to `observable` or assigning them to an `observable` property.
Making class members observable is considered the responsibility of the class constructor.
{🚀} **Tip:** observable (proxied) versus makeObservable (unproxied)
The primary difference between `make(Auto)Observable` and `observable` is that the first one modifies the object you are passing in as first argument, while `observable` creates a _clone_ that is made observable.
The second difference is that `observable` creates a [`Proxy`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) object, to be able to trap future property additions in case you use the object as a dynamic lookup map.
If the object you want to make observable has a regular structure where all members are known up-front, we recommend to use `makeObservable` as non proxied objects are a little faster, and they are easier to inspect in the debugger and `console.log`.
Because of that, `make(Auto)Observable` is the recommended API to use in factory functions.
Note that it is possible to pass `{ proxy: false }` as an option to `observable` to get a non proxied clone.
## Available annotations
| Annotation | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `observable` `observable.deep` | Defines a trackable field that stores state. If possible, any value assigned to `observable` is automatically converted to (deep) `observable`, [`autoAction`](#autoAction) or `flow` based on it's type. Only `plain object`, `array`, `Map`, `Set`, `function`, `generator function` are convertible. Class instances and others are untouched. |
| `observable.ref` | Like `observable`, but only reassignments will be tracked. The assigned values are completely ignored and will NOT be automatically converted to `observable`/[`autoAction`](#autoAction)/`flow`. For example, use this if you intend to store immutable data in an observable field. |
| `observable.shallow` | Like `observable.ref` but for collections. Any collection assigned will be made observable, but the contents of the collection itself won't become observable. |
| `observable.struct` | Like `observable`, except that any assigned value that is structurally equal to the current value will be ignored. |
| `action` | Mark a method as an action that will modify the state. Check out [actions](actions.md) for more details. Non-writable. |
| `action.bound` | Like action, but will also bind the action to the instance so that `this` will always be set. Non-writable. |
| `computed` | Can be used on a [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) to declare it as a derived value that can be cached. Check out [computeds](computeds.md) for more details. |
| `computed.struct` | Like `computed`, except that if after recomputing the result is structurally equal to the previous result, no observers will be notified. |
| `true` | Infer the best annotation. Check out [makeAutoObservable](#makeautoobservable) for more details. |
| `false` | Explicitly do not annotate this property. |
| `flow` | Creates a `flow` to manage asynchronous processes. Check out [flow](actions.md#using-flow-instead-of-async--await-) for more details. Note that the inferred return type in TypeScript might be off. Non-writable. |
| `flow.bound` | Like flow, but will also bind the flow to the instance so that `this` will always be set. Non-writable. |
| `override` | [Applicable to inherited `action`, `flow`, `computed`, `action.bound` overridden by subclass](subclassing.md). |
| `autoAction` | Should not be used explicitly, but is used under the hood by `makeAutoObservable` to mark methods that can act as action or derivation, based on their calling context. It will be determined at runtime if the function is a derivation or action. |
## Limitations
1. `make(Auto)Observable` only supports properties that are already defined. Make sure your [**compiler configuration** is correct](installation.md#use-spec-compliant-transpilation-for-class-properties), or as work-around, that a value is assigned to all properties before using `make(Auto)Observable`. Without correct configuration, fields that are declared but not initialized (like in `class X { y; }`) will not be picked up correctly.
1. `makeObservable` can only annotate properties declared by its own class definition. If a sub- or superclass introduces observable fields, it will have to call `makeObservable` for those properties itself.
1. `options` argument can be provided only once. Passed `options` are _"sticky"_ and can NOT be changed later (eg. in [subclass](subclassing.md)).
1. **Every field can be annotated only once** (except for `override`). The field annotation or configuration can't change in [subclass](subclassing.md).
1. **All annotated** fields of non-plain objects (**classes**) are **non-configurable**.
[Can be disabled with `configure({ safeDescriptors: false })` {🚀☣️} ](configuration.md#safedescriptors-boolean).
1. **All non-observable** (stateless) fields (`action`, `flow`) are **non-writable**.
[Can be disabled with `configure({ safeDescriptors: false })` {🚀☣️} ](configuration.md#safedescriptors-boolean).
1. [Only **`action`, `computed`, `flow`, `action.bound`** defined **on prototype** can be **overridden** by subclass](subclassing.md).
1. By default _TypeScript_ will not allow you to annotate **private** fields. This can be overcome by explicitly passing the relevant private fields as generic argument, like this: `makeObservable(this, { privateField: observable, privateField2: observable })`
1. **Calling `make(Auto)Observable`** and providing annotations must be done **unconditionally**, as this makes it possible to cache the inference results.
1. **Modifying prototypes** after **`make(Auto)Observable`** has been called is **not supported**.
1. _EcmaScript_ **private** fields (**`#field`**) are **not supported** by `make(Auto)Observable`. Use auto-accessor + Stage-3 decorators (`@observable accessor #field`) syntax instead. Otherwise, when using _TypeScript_, it is recommended to use the `private` modifier.
1. **Mixing annotations and decorators** within single inheritance chain is **not supported** - eg. you can't use decorators for superclass and annotations for subclass.
1. `makeObservable`,`extendObservable` cannot be used on other builtin observable types (`ObservableMap`, `ObservableSet`, `ObservableArray`, etc)
1. `makeObservable(Object.create(prototype))` copies properties from `prototype` to created object and makes them `observable`. This behavior is wrong, unexpected and therefore **deprecated** and will likely change in future versions. Don't rely on it.
## Options {🚀}
The above APIs take an optional `options` argument which is an object that supports the following options:
- **`autoBind: true`** uses `action.bound`/`flow.bound` by default, rather than `action`/`flow`. Does not affect explicitely annotated members.
- **`deep: false`** uses `observable.ref` by default, rather than `observable`. Does not affect explicitely annotated members.
- **`name: `** gives the object a debug name that is printed in error messages and reflection APIs.
- **`proxy: false`** forces `observable(thing)` to use non-[**proxy**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) implementation. This is a good option if the shape of the object will not change over time, as non-proxied objects are easier to debug and faster. This option is **not** available for `make(Auto)Observable`, see [avoiding proxies](#avoid-proxies).
**Note:** options are *sticky* and can be provided only once
`options` argument can be provided only for `target` that is NOT observable yet.
It is NOT possible to change options once the observable object was initialized.
Options are stored on target and respected by subsequent `makeObservable`/`extendObservable` calls.
You can't pass different options in [subclass](subclassing.md).
## Converting observables back to vanilla JavaScript collections
Sometimes it is necessary to convert observable data structures back to their vanilla counterparts.
For example when passing observable objects to a React component that can't track observables, or to obtain a clone that should not be further mutated.
To convert a collection shallowly, the usual JavaScript mechanisms work:
```javascript
const plainObject = { ...observableObject }
const plainArray = observableArray.slice()
const plainMap = new Map(observableMap)
```
To convert a data tree recursively to plain objects, the [`toJS`](api.md#tojs) utility can be used.
For classes, it is recommended to implement a `toJSON()` method, as it will be picked up by `JSON.stringify`.
## A short note on classes
So far most examples above have been leaning towards the class syntax.
MobX is in principle unopinionated about this, and there are probably just as many MobX users that use plain objects.
However, a slight benefit of classes is that they have more easily discoverable APIs, e.g. TypeScript.
Also, `instanceof` checks are really powerful for type inference, and class instances aren't wrapped in `Proxy` objects, giving them a better experience in debuggers.
Finally, classes benefit from a lot of engine optimizations, since their shape is predictable, and methods are shared on the prototype.
But heavy inheritance patterns can easily become foot-guns, so if you use classes, keep them simple.
So, even though there is a slight preference to use classes, we definitely want to encourage you to deviate from this style if that suits you better.
---
---
title: React integration
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../react-integration.md)
---
---
title: Optimizing React component rendering
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../react-optimizations.md)
---
---
title: React integration
sidebar_label: React integration
hide_title: true
---
# React integration
This documentation outlines how to manually apply observation to React components. However, by using the [mobx-react-observer](https://github.com/christianalfoni/mobx-react-observer) Babel/SWC plugin, you can automatically handle observation without manual intervention. Still, understanding how MobX observation integrates with React components remains valuable, even when leveraging automated solutions.
```javascript
import { observer } from "mobx-react-lite" // Or "mobx-react".
const MyComponent = observer(props => ReactElement)
```
While MobX works independently from React, they are most commonly used together. In [The gist of MobX](the-gist-of-mobx.md) you have already seen the most important part of this integration: the `observer` [HoC](https://reactjs.org/docs/higher-order-components.html) that you can wrap around a React component.
`observer` is provided by a separate React bindings package you choose [during installation](installation.md#installation). In this example, we're going to use the more lightweight [`mobx-react-lite` package](https://github.com/mobxjs/mobx/tree/main/packages/mobx-react-lite).
```javascript
import React from "react"
import ReactDOM from "react-dom"
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react-lite"
class Timer {
secondsPassed = 0
constructor() {
makeAutoObservable(this)
}
increaseTimer() {
this.secondsPassed += 1
}
}
const myTimer = new Timer()
// A function component wrapped with `observer` will react
// to any future change in an observable it used before.
const TimerView = observer(({ timer }) => Seconds passed: {timer.secondsPassed})
ReactDOM.render(, document.body)
setInterval(() => {
myTimer.increaseTimer()
}, 1000)
```
**Hint:** you can play with the above example yourself on [CodeSandbox](https://codesandbox.io/s/minimal-observer-p9ti4?file=/src/index.tsx).
The `observer` HoC automatically subscribes React components to _any observables_ that are used _during rendering_.
As a result, components will automatically re-render when relevant observables change.
It also makes sure that components don't re-render when there are _no relevant_ changes.
So, observables that are accessible by the component, but not actually read, won't ever cause a re-render.
In practice this makes MobX applications very well optimized out of the box and they typically don't need any additional code to prevent excessive rendering.
For `observer` to work, it doesn't matter _how_ the observables arrive in the component, only that they are read.
Reading observables deeply is fine, complex expression like `todos[0].author.displayName` work out of the box.
This makes the subscription mechanism much more precise and efficient compared to other frameworks in which data dependencies have to be declared explicitly or be pre-computed (e.g. selectors).
## Local and external state
There is great flexibility in how state is organized, since it doesn't matter (technically that is) which observables we read or where observables originated from.
The examples below demonstrate different patterns on how external and local observable state can be used in components wrapped with `observer`.
### Using external state in `observer` components
Observables can be passed into components as props (as in the example above):
```javascript
import { observer } from "mobx-react-lite"
const myTimer = new Timer() // See the Timer definition above.
const TimerView = observer(({ timer }) => Seconds passed: {timer.secondsPassed})
// Pass myTimer as a prop.
ReactDOM.render(, document.body)
```
Since it doesn't matter _how_ we got the reference to an observable, we can consume
observables from outer scopes directly (including from imports, etc.):
```javascript
const myTimer = new Timer() // See the Timer definition above.
// No props, `myTimer` is directly consumed from the closure.
const TimerView = observer(() => Seconds passed: {myTimer.secondsPassed})
ReactDOM.render(, document.body)
```
Using observables directly works very well, but since this typically introduces module state, this pattern might complicate unit testing. Instead, we recommend using React Context instead.
[React Context](https://reactjs.org/docs/context.html) is a great mechanism to share observables with an entire subtree:
```javascript
import {observer} from 'mobx-react-lite'
import {createContext, useContext} from "react"
const TimerContext = createContext()
const TimerView = observer(() => {
// Grab the timer from the context.
const timer = useContext(TimerContext) // See the Timer definition above.
return (
Seconds passed: {timer.secondsPassed}
)
})
ReactDOM.render(
,
document.body
)
```
Note that we don't recommend ever replacing the `value` of a `Provider` with a different one. Using MobX, there should be no need for that, since the observable that is shared can be updated itself.
### Using local observable state in `observer` components
Since observables used by `observer` can come from anywhere, they can be local state as well.
Again, different options are available for us.
The simplest way to use local observable state is to store a reference to an observable class with `useState`.
Note that, since we typically don't want to replace the reference, we totally ignore the updater function returned by `useState`:
```javascript
import { observer } from "mobx-react-lite"
import { useState } from "react"
const TimerView = observer(() => {
const [timer] = useState(() => new Timer()) // See the Timer definition above.
return Seconds passed: {timer.secondsPassed}
})
ReactDOM.render(, document.body)
```
If you want to automatically update the timer like we did in the original example,
`useEffect` could be used in typical React fashion:
```javascript
useEffect(() => {
const handle = setInterval(() => {
timer.increaseTimer()
}, 1000)
return () => {
clearInterval(handle)
}
}, [timer])
```
As stated before, instead of using classes, it is possible to directly create observable objects.
We can leverage [observable](observable-state.md#observable) for that:
```javascript
import { observer } from "mobx-react-lite"
import { observable } from "mobx"
import { useState } from "react"
const TimerView = observer(() => {
const [timer] = useState(() =>
observable({
secondsPassed: 0,
increaseTimer() {
this.secondsPassed++
}
})
)
return Seconds passed: {timer.secondsPassed}
})
ReactDOM.render(, document.body)
```
The combination `const [store] = useState(() => observable({ /* something */}))` is
quite common. To make this pattern simpler the [`useLocalObservable`](https://github.com/mobxjs/mobx-react#uselocalobservable-hook) hook is exposed from `mobx-react-lite` package, making it possible to simplify the earlier example to:
```javascript
import { observer, useLocalObservable } from "mobx-react-lite"
const TimerView = observer(() => {
const timer = useLocalObservable(() => ({
secondsPassed: 0,
increaseTimer() {
this.secondsPassed++
}
}))
return Seconds passed: {timer.secondsPassed}
})
ReactDOM.render(, document.body)
```
### You might not need locally observable state
In general, we recommend to not resort to MobX observables for local component state too quickly, as this can theoretically lock you out of some features of React's Suspense mechanism.
As a rule of thumb, use MobX observables when the state captures domain data that is shared among components (including children). Such as todo items, users, bookings, etc.
State that only captures UI state, like loading state, selections, etc, might be better served by the [`useState` hook](https://reactjs.org/docs/hooks-state.html), since this will allow you to leverage React suspense features in the future.
Using observables inside React components adds value as soon as they are either 1) deep, 2) have computed values or 3) are shared with other `observer` components.
## Always read observables inside `observer` components
You might be wondering, when do I apply `observer`? The rule of thumb is: _apply `observer` to all components that read observable data_.
`observer` only enhances the component you are decorating, not the components called by it. So usually all your components should be wrapped by `observer`. Don't worry, this is not inefficient. On the contrary, more `observer` components make rendering more efficient as updates become more fine-grained.
### Tip: Grab values from objects as late as possible
`observer` works best if you pass object references around as long as possible, and only read their properties inside the `observer` based components that are going to render them into the DOM / low-level components.
In other words, `observer` reacts to the fact that you 'dereference' a value from an object.
In the above example, the `TimerView` component would **not** react to future changes if it was defined
as follows, because the `.secondsPassed` is not read inside the `observer` component, but outside, and is hence _not_ tracked:
```javascript
const TimerView = observer(({ secondsPassed }) => Seconds passed: {secondsPassed})
React.render(, document.body)
```
Note that this is a different mindset from other libraries like `react-redux`, where it is a good practice to dereference early and pass primitives down, to better leverage memoization.
If the problem is not entirely clear, make sure to check out the [Understanding reactivity](understanding-reactivity.md) section.
### Don't pass observables into components that aren't `observer`
Components wrapped with `observer` _only_ subscribe to observables used during their _own_ rendering of the component. So if observable objects / arrays / maps are passed to child components, those have to be wrapped with `observer` as well.
This is also true for any callback based components.
If you want to pass observables to a component that isn't an `observer`, either because it is a third-party component, or because you want to keep that component MobX agnostic, you will have to [convert the observables to plain JavaScript values or structures](observable-state.md#converting-observables-back-to-vanilla-javascript-collections) before passing them on.
To elaborate on the above,
take the following example observable `todo` object, a `TodoView` component (observer) and an imaginary `GridRow` component that takes a column / value mapping, but which isn't an `observer`:
```javascript
class Todo {
title = "test"
done = true
constructor() {
makeAutoObservable(this)
}
}
const TodoView = observer(({ todo }: { todo: Todo }) =>
// WRONG: GridRow won't pick up changes in todo.title / todo.done
// since it isn't an observer.
return
// CORRECT: let `TodoView` detect relevant changes in `todo`,
// and pass plain data down.
return
// CORRECT: using `toJS` works as well, but being explicit is typically better.
return
)
```
### Callback components might require ``
Imagine the same example, where `GridRow` takes an `onRender` callback instead.
Since `onRender` is part of the rendering cycle of `GridRow`, rather than `TodoView`'s render (even though that is where it syntactically appears), we have to make sure that the callback component uses an `observer` component.
Or, we can create an in-line anonymous observer using [``](https://github.com/mobxjs/mobx-react#observer):
```javascript
const TodoView = observer(({ todo }: { todo: Todo }) => {
// WRONG: GridRow.onRender won't pick up changes in todo.title / todo.done
// since it isn't an observer.
return
{todo.title}
} />
// CORRECT: wrap the callback rendering in Observer to be able to detect changes.
return {() =>
{todo.title}
}} />
})
```
## Tips
Server Side Rendering (SSR)
If `observer` is used in server side rendering context; make sure to call `enableStaticRendering(true)`, so that `observer` won't subscribe to any observables used, and no GC problems are introduced.
**Note:** mobx-react vs. mobx-react-lite
In this documentation we used `mobx-react-lite` as default.
[mobx-react](https://github.com/mobxjs/mobx-react/) is it's big brother, which uses `mobx-react-lite` under the hood.
It offers a few more features which are typically not needed anymore in greenfield projects. The additional things offered by mobx-react:
1. Support for React class components.
1. `Provider` and `inject`. MobX's own React.createContext predecessor which is not needed anymore.
1. Observable specific `propTypes`.
Note that `mobx-react` fully repackages and re-exports `mobx-react-lite`, including functional component support.
If you use `mobx-react`, there is no need to add `mobx-react-lite` as a dependency or import from it anywhere.
**Note:** `observer` or `React.memo`?
`observer` automatically applies `memo`, so `observer` components never need to be wrapped in `memo`.
`memo` can be applied safely to observer components because mutations (deeply) inside the props will be picked up by `observer` anyway if relevant.
**Tip:** `observer` for class based React components
As stated above, class based components are only supported through `mobx-react`, and not `mobx-react-lite`.
Briefly, you can wrap class-based components in `observer` just like
you can wrap function components:
```javascript
import React from "React"
const TimerView = observer(
class TimerView extends React.Component {
render() {
const { timer } = this.props
return Seconds passed: {timer.secondsPassed}
}
}
)
```
Check out [mobx-react docs](https://github.com/mobxjs/mobx/tree/main/packages/mobx-react#class-components) for more information.
**Tip:** nice component names in React DevTools
[React DevTools](https://reactjs.org/blog/2019/08/15/new-react-devtools.html) uses the display name information of components to properly display the component hierarchy.
If you use:
```javascript
export const MyComponent = observer(props =>
hi
)
```
then no display name will be visible in the DevTools.

The following approaches can be used to fix this:
- use `function` with a name instead of an arrow function. `mobx-react` infers component name from the function name:
```javascript
export const MyComponent = observer(function MyComponent(props) {
return
hi
})
```
- Transpilers (like Babel or TypeScript) infer component name from the variable name:
```javascript
const _MyComponent = props =>
hi
export const MyComponent = observer(_MyComponent)
```
- Infer from the variable name again, using default export:
```javascript
const MyComponent = props =>
)
MyComponent.displayName = "MyComponent"
```
This is broken in React 16 at the time of writing; mobx-react `observer` uses a React.memo and runs into this bug: https://github.com/facebook/react/issues/18026, but it will be fixed in React 17.
Now you can see component names:

{🚀} **Tip:** when combining `observer` with other higher-order-components, apply `observer` first
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.
{🚀} **Tip:** deriving computeds from props
In some cases the computed values of your local observables might depend on some of the props your component receives.
However, the set of props that a React component receives is in itself not observable, so changes to the props won't be reflected in any computed values. You have to manually update local observable state in order to properly derive computed values from latest data.
```javascript
import { observer, useLocalObservable } from "mobx-react-lite"
import { useEffect } from "react"
const TimerView = observer(({ offset = 0 }) => {
const timer = useLocalObservable(() => ({
offset, // The initial offset value
secondsPassed: 0,
increaseTimer() {
this.secondsPassed++
},
get offsetTime() {
return this.secondsPassed - this.offset // Not 'offset' from 'props'!
}
}))
useEffect(() => {
// Sync the offset from 'props' into the observable 'timer'
timer.offset = offset
}, [offset])
// Effect to set up a timer, only for demo purposes.
useEffect(() => {
const handle = setInterval(timer.increaseTimer, 1000)
return () => {
clearInterval(handle)
}
}, [])
return Seconds passed: {timer.offsetTime}
})
ReactDOM.render(, document.body)
```
In practice you will rarely need this pattern, since
`return Seconds passed: {timer.secondsPassed - offset}`
is a much simpler, albeit slightly less efficient solution.
{🚀} **Tip:** useEffect and observables
`useEffect` can be used to set up side effects that need to happen, and which are bound to the life-cycle of the React component.
Using `useEffect` requires specifying dependencies.
With MobX that isn't really needed, since MobX has already a way to automatically determine the dependencies of an effect, `autorun`.
Combining `autorun` and coupling it to the life-cycle of the component using `useEffect` is luckily straightforward:
```javascript
import { observer, useLocalObservable, useAsObservableSource } from "mobx-react-lite"
import { useState } from "react"
const TimerView = observer(() => {
const timer = useLocalObservable(() => ({
secondsPassed: 0,
increaseTimer() {
this.secondsPassed++
}
}))
// Effect that triggers upon observable changes.
useEffect(
() =>
autorun(() => {
if (timer.secondsPassed > 60) alert("Still there. It's a minute already?!!")
}),
[]
)
// Effect to set up a timer, only for demo purposes.
useEffect(() => {
const handle = setInterval(timer.increaseTimer, 1000)
return () => {
clearInterval(handle)
}
}, [])
return Seconds passed: {timer.secondsPassed}
})
ReactDOM.render(, document.body)
```
Note that we return the disposer created by `autorun` from our effect function.
This is important, since it makes sure the `autorun` gets cleaned up once the component unmounts!
The dependency array can typically be left empty, unless a non-observable value should trigger a re-run of the autorun, in which case you will need to add it there.
To make your linter happy, you can define `timer` (in the above example) as a dependency.
That is safe and has no further effect, since the reference will never actually change.
If you'd rather explicitly define which observables should trigger the effect, use `reaction` instead of `autorun`, beyond that the pattern remains identical.
### How can I further optimize my React components?
Check out the [React optimizations {🚀}](react-optimizations.md) section.
## Troubleshooting
Help! My component isn't re-rendering...
1. Make sure you didn't forget `observer` (yes, this is the most common mistake).
1. Verify that the thing you intend to react to is indeed observable. Use utilities like [`isObservable`](api.md#isobservable), [`isObservableProp`](api.md#isobservableprop) if needed to verify this at runtime.
1. Check the console logs in the browsers for any warnings or errors.
1. Make sure you grok how tracking works in general. Check out the [Understanding reactivity](understanding-reactivity.md) section.
1. Read the common pitfalls as described above.
1. [Configure](configuration.md#linting-options) MobX to warn you of unsound usage of mechanisms and check the console logs.
1. Use [trace](analyzing-reactivity.md) to verify that you are subscribing to the right things or check what MobX is doing in general using [spy](analyzing-reactivity.md#spy) / the [mobx-log](https://github.com/kubk/mobx-log) package.
---
---
title: Optimizing React component rendering
sidebar_label: React optimizations {🚀}
hide_title: true
---
# Optimizing React component rendering {🚀}
MobX is very fast, [often even faster than Redux](https://twitter.com/mweststrate/status/718444275239882753), but here are some tips to get most out of React and MobX. Most apply to React in general and are not specific to MobX.
Note that while it's good to be aware of these patterns, usually your application
will be fast enough even if you don't worry about them at all.
Prioritize performance only when it's an actual issue!
## Use many small components
`observer` components will track all values they use and re-render if any of them changes.
So the smaller your components are, the smaller the change they have to re-render. It means that more parts of your user interface have the possibility to render independently of each other.
## Render lists in dedicated components
The above is especially true when rendering big collections.
React is notoriously bad at rendering large collections as the reconciler has to evaluate the components produced by a collection on each collection change.
It is therefore recommended to have components that just map over a collection and render it, and render nothing else.
Bad:
```javascript
const MyComponent = observer(({ todos, user }) => (
{user.name}
{todos.map(todo => (
))}
))
```
In the above listing React will unnecessarily need to reconcile all `TodoView` components when the `user.name` changes. They won't re-render, but the reconcile process is expensive in itself.
Good:
```javascript
const MyComponent = observer(({ todos, user }) => (
{user.name}
))
const TodosView = observer(({ todos }) => (
{todos.map(todo => (
))}
))
```
## Don't use array indexes as keys
Don't use array indexes or any value that might change in the future as key. Generate ids for your objects if needed.
Check out this [blog post](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318).
## Dereference values late
When using `mobx-react` it is recommended to dereference values as late as possible.
This is because MobX will re-render components that dereference observable values automatically.
If this happens deeper in your component tree, less components have to re-render.
Slower:
```javascript
```
Faster:
```javascript
```
In the faster example, a change in the `name` property triggers only `DisplayName` to re-render, while in the slower one the owner of the component has to re-render as well. There is nothing wrong with that, and if rendering of the owning component is fast enough (usually it is!), then this approach works well.
### Function props {🚀}
You may notice that to dereference values late, you have to create lots of small observer components where each is customized to render a different part of data, for example:
```javascript
const PersonNameDisplayer = observer(({ person }) => )
const CarNameDisplayer = observer(({ car }) => )
const ManufacturerNameDisplayer = observer(({ car }) =>
)
```
This quickly becomes tedious if you have lots of data of different shape. An alternative is to use a function that returns the data that you want your `*Displayer` to render:
```javascript
const GenericNameDisplayer = observer(({ getName }) => )
```
Then, you can use the component like this:
```javascript
const MyComponent = ({ person, car }) => (
<>
person.name} />
car.model} />
car.manufacturer.name} />
>
)
```
This approach will allow `GenericNameDisplayer` to be reused throughout your application to render any name, and you still keep component re-rendering
to a minimum.
---
---
title: Running side effects with reactions
sidebar_label: Reactions {🚀}
hide_title: true
---
# Running side effects with reactions {🚀}
Reactions are an important concept to understand, as it is where everything in MobX comes together.
The goal of reactions is to model side effects that happen automatically.
Their significance is in creating consumers for your observable state and _automatically_ running side effects whenever something _relevant_ changes.
However, with that in mind, it is important to realize that the APIs discussed here should rarely be used.
They are often abstracted away in other libraries (like mobx-react) or abstractions specific to your application.
But, to grok MobX, let's take a look at how reactions can be created.
The simplest way is to use the [`autorun`](#autorun) utility.
Beyond that, there are also [`reaction`](#reaction) and [`when`](#when).
## Autorun
Usage:
- `autorun(effect: (reaction) => void, options?)`
The `autorun` function accepts one function that should run every time anything it observes changes.
It also runs once when you create the `autorun` itself. It only responds to changes in observable state, things you have annotated `observable` or `computed`.
### How tracking works
Autorun works by running the `effect` in a _reactive context_. During the execution of the provided function, MobX keeps track of all observable and computed values that are directly or indirectly _read_ by the effect.
Once the function finishes, MobX will collect and subscribe to all observables that were read and wait until any of them changes again.
Once they do, the `autorun` will trigger again, repeating the entire process.

This is how the example below works like.
### Example
```javascript
import { makeAutoObservable, autorun } from "mobx"
class Animal {
name
energyLevel
constructor(name) {
this.name = name
this.energyLevel = 100
makeAutoObservable(this)
}
reduceEnergy() {
this.energyLevel -= 10
}
get isHungry() {
return this.energyLevel < 50
}
}
const giraffe = new Animal("Gary")
autorun(() => {
console.log("Energy level:", giraffe.energyLevel)
})
autorun(() => {
if (giraffe.isHungry) {
console.log("Now I'm hungry!")
} else {
console.log("I'm not hungry!")
}
})
console.log("Now let's change state!")
for (let i = 0; i < 10; i++) {
giraffe.reduceEnergy()
}
```
Running this code, you will get the following output:
```
Energy level: 100
I'm not hungry!
Now let's change state!
Energy level: 90
Energy level: 80
Energy level: 70
Energy level: 60
Energy level: 50
Energy level: 40
Now I'm hungry!
Energy level: 30
Energy level: 20
Energy level: 10
Energy level: 0
```
As you can see in the first two lines of the output above, both `autorun` functions run once when they are initialized. This is all you would see without the `for` loop.
Once we run the `for` loop to change the `energyLevel` with the `reduceEnergy`
action, we see a new log entry every time an `autorun` function observes a
change in its observable state:
1. For the _"Energy level"_ function, this is every time the `energyLevel` observable changes, 10 times in total.
2. For the _"Now I'm hungry"_ function, this is every time the `isHungry` computed
changes, only one time.
## Reaction
Usage:
- `reaction(() => value, (value, previousValue, reaction) => { sideEffect }, options?)`.
`reaction` is like `autorun`, but gives more fine grained control on which observables will be tracked.
It takes two functions: the first, _data_ function, is tracked and returns the data that is used as input for the second, _effect_ function.
It is important to note that the side effect _only_ reacts to data that was _accessed_ in the data function, which might be less than the data that is actually used in the effect function.
The typical pattern is that you produce the things you need in your side effect
in the _data_ function, and in that way control more precisely when the effect triggers.
By default, the result of the _data_ function has to change in order for the _effect_ function to be triggered.
Unlike `autorun`, the side effect won't run once when initialized, but only after the data expression returns a new value for the first time.
**Example:** the data and effect functions
In the example below, the reaction is only triggered once, when `isHungry` changes.
Changes to `giraffe.energyLevel`, which is used by the _effect_ function, do not cause the _effect_ function to be executed. If you wanted `reaction` to respond to this
as well, you would have to also access it in the _data_ function and return it.
```javascript
import { makeAutoObservable, reaction } from "mobx"
class Animal {
name
energyLevel
constructor(name) {
this.name = name
this.energyLevel = 100
makeAutoObservable(this)
}
reduceEnergy() {
this.energyLevel -= 10
}
get isHungry() {
return this.energyLevel < 50
}
}
const giraffe = new Animal("Gary")
reaction(
() => giraffe.isHungry,
isHungry => {
if (isHungry) {
console.log("Now I'm hungry!")
} else {
console.log("I'm not hungry!")
}
console.log("Energy level:", giraffe.energyLevel)
}
)
console.log("Now let's change state!")
for (let i = 0; i < 10; i++) {
giraffe.reduceEnergy()
}
```
Output:
```
Now let's change state!
Now I'm hungry!
Energy level: 40
```
## When
Usage:
- `when(predicate: () => boolean, effect?: () => void, options?)`
- `when(predicate: () => boolean, options?): Promise`
`when` observes and runs the given _predicate_ function until it returns `true`.
Once that happens, the given _effect_ function is executed and the autorunner is disposed.
The `when` function returns a disposer, allowing you to cancel it manually, unless you don't pass in a second `effect` function, in which case it returns a `Promise`.
**Example:** dispose of things in a reactive way
`when` is really useful for disposing or canceling of things in a reactive way.
For example:
```javascript
import { when, makeAutoObservable } from "mobx"
class MyResource {
constructor() {
makeAutoObservable(this, { dispose: false })
when(
// Once...
() => !this.isVisible,
// ... then.
() => this.dispose()
)
}
get isVisible() {
// Indicate whether this item is visible.
}
dispose() {
// Clean up some resources.
}
}
```
As soon as `isVisible` becomes `false`, the `dispose` method is called that
then does some cleanup for `MyResource`.
### `await when(...)`
If no `effect` function is provided, `when` returns a `Promise`. This combines nicely with `async / await` to let you wait for changes in observable state.
```javascript
async function() {
await when(() => that.isVisible)
// etc...
}
```
To cancel `when` prematurely, it is possible to call `.cancel()` on the promise returned by itself.
## Rules
There are a few rules that apply to any reactive context:
1. Affected reactions run by default immediately (synchronously) if an observable is changed. However, they won't run before the end of the current outermost (trans)action.
2. Autorun tracks only the observables that are read during the synchronous execution of the provided function, but it won't track anything that happens asynchronously.
3. Autorun won't track observables that are read by an action invoked by the autorun, as actions are always _untracked_.
For more examples on what precisely MobX will and will not react to, check out the [Understanding reactivity](understanding-reactivity.md) section.
For a more detailed technical breakdown on how tracking works, read the blog post [Becoming fully reactive: an in-depth explanation of MobX](https://hackernoon.com/becoming-fully-reactive-an-in-depth-explanation-of-mobservable-55995262a254).
## Always dispose of reactions
The functions passed to `autorun`, `reaction` and `when` are only garbage collected if all objects they observe are garbage collected themselves. In principle, they keep waiting forever for new changes to happen in the observables they use.
To be able to stop them from waiting until forever has passed, they all return a disposer function that can be used to stop them and unsubscribe from any observables they used.
```javascript
const counter = observable({ count: 0 })
// Sets up the autorun and prints 0.
const disposer = autorun(() => {
console.log(counter.count)
})
// Prints: 1
counter.count++
// Stops the autorun.
disposer()
// Will not print.
counter.count++
```
We strongly recommend to always use the disposer function that is returned from these methods as soon as their side effect is no longer needed.
Failing to do so can lead to memory leaks.
The `reaction` argument that is passed as second argument to the effect functions of `reaction` and `autorun`, can be used to prematurely clean up the reaction as well by calling `reaction.dispose()`.
**Example:** memory leak
```javascript
class Vat {
value = 1.2
constructor() {
makeAutoObservable(this)
}
}
const vat = new Vat()
class OrderLine {
price = 10
amount = 1
constructor() {
makeAutoObservable(this)
// This autorun will be GC-ed together with the current orderline
// instance as it only uses observables from `this`. It's not strictly
// necessary to dispose of it once an OrderLine instance is deleted.
this.disposer1 = autorun(() => {
doSomethingWith(this.price * this.amount)
})
// This autorun won't be GC-ed together with the current orderline
// instance, since vat keeps a reference to notify this autorun, which
// in turn keeps 'this' in scope.
this.disposer2 = autorun(() => {
doSomethingWith(this.price * this.amount * vat.value)
})
}
dispose() {
// So, to avoid subtle memory issues, always call the
// disposers when the reactions are no longer needed.
this.disposer1()
this.disposer2()
}
}
```
In environments that support [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management),
the disposer function includes a `[Symbol.dispose]` method that can be used to
dispose of the reaction. This can be useful when disposing of several reactions
simultaneously or when disposing of reactions alongside other Disposables.
**Example:** using DisposableStack
```javascript
function createSomeDisposableResource() {}
class Vat {
value = 1.2
constructor() {
makeAutoObservable(this)
}
}
const vat = new Vat()
class OrderLine {
price = 10
amount = 1
disposableStack = new DisposableStack()
someDisposableResource
constructor() {
makeAutoObservable(this)
this.disposableStack.use(autorun(() => {
doSomethingWith(this.price * this.amount)
}))
this.disposableStack.use(autorun(() => {
doSomethingWith(this.price * this.amount * vat.value)
}))
this.someDisposableResource = this.disposableStack.use(createSomeDisposableResource())
}
[Symbol.dispose]() {
this.disposableStack[Symbol.dispose]();
}
}
```
## Use reactions sparingly!
As it was already said, you won't create reactions very often.
It might very well be that your application doesn't use any of these APIs directly, and the only way reactions are constructed is indirectly, through for example `observer` from the mobx-react bindings.
Before you set up a reaction, it is good to first check if it conforms to the following principles:
1. **Only use Reactions if there is no direct relation between cause and effect**: If a side effect should happen in response to a very limited set of events / actions, it will often be clearer to directly trigger the effect from those specific actions. For example, if pressing a form submit button should lead to a network request to be posted, it is clearer to trigger this effect directly in response of the `onClick` event, rather than indirectly through a reaction. In contrast, if any change you make to the form state should automatically end up in local storage, then a reaction can be very useful, so that you don't have to trigger this effect from every individual `onChange` event.
1. **Reactions shouldn't update other observables**: Is the reaction going to modify other observables? If the answer is yes, typically the observable you want to update should be annotated as a [`computed`](computeds.md) value instead. For example, if a collection of todos is altered, don't use a reaction to compute the amount of `remainingTodos`, but annotate `remainingTodos` as a computed value. That will lead to much clearer and easier to debug code. Reactions should not compute new data, but only cause effects.
1. **Reactions should be independent**: Does your code rely on some other reaction having to run first? If that is the case, you probably
either violated the first rule, or the new reaction you are about to create should be merged into the one it is depending upon. MobX does not guarantee the order in which reactions will be run.
There are real-life scenarios that do not fit in the above principles. That is why they are _principles_, not _laws_.
But, the exceptions are rare so only violate them as a last resort.
## Options {🚀}
The behavior of `autorun`, `reaction` and `when` can be further fine-tuned by passing in an `options` argument as shown in the usages above.
### `name`
This string is used as a debug name for this reaction in the [Spy event listeners](analyzing-reactivity.md#spy) and [MobX developer tools](https://github.com/mobxjs/mobx-devtools).
### `fireImmediately` _(reaction)_
Boolean indicating that the _effect_ function should immediately be triggered after the first run of the _data_ function. `false` by default.
### `delay` _(autorun, reaction)_
Number of milliseconds that can be used to throttle the effect function. If zero (default), no throttling happens.
### `timeout` _(when)_
Set a limited amount of time that `when` will wait for. If the deadline passes, `when` will reject / throw.
### `signal`
An AbortSignal object instance; can be used as an alternative method for disposal.
When used with promise version of `when`, the promise rejects with the "WHEN_ABORTED" error.
### `onError`
By default, any exception thrown inside an reaction will be logged, but not further thrown. This is to make sure that an exception in one reaction does not prevent the scheduled execution of other, possibly unrelated reactions. This also allows reactions to recover from exceptions. Throwing an exception does not break the tracking done by MobX, so subsequent runs of the reaction might complete normally again if the cause for the exception is removed. This option allows overriding that behavior. It is possible to set a global error handler or to disable catching errors completely using [configure](configuration.md#disableerrorboundaries-boolean).
### `scheduler` _(autorun, reaction)_
Set a custom scheduler to determine how re-running the autorun function should be scheduled. It takes a function that should be invoked at some point in the future, for example: `{ scheduler: run => { setTimeout(run, 1000) }}`
### `equals`: (reaction)
Set to `comparer.default` by default. If specified, this comparer function is used to compare the previous and next values produced by the _data_ function. The _effect_ function is only invoked if this function returns false.
Check out the [Built-in comparers](computeds.md#built-in-comparers) section.
---
---
title: Updating state using actions
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../actions.md)
---
---
title: MobX API overview
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../api.md)
---
---
title: Running side effects with reactions
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../reactions.md)
---
---
title: Computeds with arguments
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../computeds-with-args.md)
---
---
title: Deriving information with computeds
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../computeds.md)
---
---
title: Configuration
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../configuration.md)
---
---
title: Creating custom observables
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../custom-observables.md)
---
---
title: MobX-utils
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../mobx-utils.md)
---
---
title: Observable modifiers
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../observable-state.md#available-annotations)
---
---
title: Collection utilities
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../collection-utilities.md)
---
---
title: Observable Objects
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../api.md#observableobject)
---
---
title: Creating observable state
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../observable-state.md)
---
---
title: Intercept & Observe
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../intercept-and-observe.md)
---
---
title: Creating lazy observables
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../lazy-observables.md)
---
---
title: Observable Sets
hide_title: true
---
# This document has been updated and moved
[Please click on this link to open the updated version.](../api.md#observableset)
---
---
title: Subclassing
sidebar_label: Subclassing
hide_title: true
---
# Subclassing
Subclassing is supported with [limitations](#limitations). Most notably you can only **override actions/flows/computeds on prototype** - you cannot override _[field declarations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#field_declarations)_. Use the `override` annotation for methods/getters overridden in a subclass - see example below. Try to keep things simple and prefer composition over inheritance.
```javascript
import { makeObservable, observable, computed, action, override } from "mobx"
class Parent {
// Annotated instance fields are NOT overridable
observable = 0
arrowAction = () => {}
// Non-annotated instance fields are overridable
overridableArrowAction = action(() => {})
// Annotated prototype methods/getters are overridable
action() {}
actionBound() {}
get computed() {}
constructor(value) {
makeObservable(this, {
observable: observable,
arrowAction: action
action: action,
actionBound: action.bound,
computed: computed,
})
}
}
class Child extends Parent {
/* --- INHERITED --- */
// THROWS - TypeError: Cannot redefine property
// observable = 5
// arrowAction = () = {}
// OK - not annotated
overridableArrowAction = action(() => {})
// OK - prototype
action() {}
actionBound() {}
get computed() {}
/* --- NEW --- */
childObservable = 0;
childArrowAction = () => {}
childAction() {}
childActionBound() {}
get childComputed() {}
constructor(value) {
super()
makeObservable(this, {
// inherited
action: override,
actionBound: override,
computed: override,
// new
childObservable: observable,
childArrowAction: action
childAction: action,
childActionBound: action.bound,
childComputed: computed,
})
}
}
```
## Limitations
1. Only `action`, `computed`, `flow`, `action.bound` defined **on prototype** can be **overridden** by subclass.
1. Field can't be re-annotated in subclass, except with `override`.
1. `makeAutoObservable` does not support subclassing.
1. Extending builtins (`ObservableMap`, `ObservableArray`, etc) is not supported.
1. You can't provide different options to `makeObservable` in subclass.
1. You can't mix annotations/decorators in single inheritance chain.
1. [All other limitations apply as well](observable-state.html#limitations)
### `TypeError: Cannot redefine property`
If you see this, you're probably trying to **override arrow function** in subclass `x = () => {}`. That's not possible because **all annotated** fields of classes are **non-configurable** ([see limitations](observable-state.md#limitations)). You have two options:
1. Move function to prototype and use `action.bound` annotation instead
```javascript
class Parent {
// action = () => {};
// =>
action() {}
constructor() {
makeObservable(this, {
action: action.bound
})
}
}
class Child {
action() {}
constructor() {
super()
makeObservable(this, {
action: override
})
}
}
```
2. Remove `action` annotation and wrap the function in action manually: `x = action(() => {})`
```javascript
class Parent {
// action = () => {};
// =>
action = action(() => {})
constructor() {
makeObservable(this, {}) // <-- annotation removed
}
}
class Child {
action = action(() => {})
constructor() {
super()
makeObservable(this, {}) // <-- annotation removed
}
}
```
---
---
title: The gist of MobX
sidebar_label: The gist of MobX
hide_title: true
---
# The gist of MobX
## Concepts
MobX distinguishes between the following three concepts in your application:
1. State
2. Actions
3. Derivations
Let's take a closer look at these concepts below, or alternatively, in the [10 minute introduction to MobX and React](https://mobx.js.org/getting-started), where you can interactively dive deeper into these concepts step by step and build a simple Todo list app.
Some might recognise the concept of "Signals" in the concepts described below.
This is correct, MobX is a signal based state management library avant la lettre.
### 1. Define state and make it observable
_State_ is the data that drives your application.
Usually, there is _domain specific state_ like a list of todo items, and there is _view state_, such as the currently selected element.
State is like spreadsheet cells that hold a value.
Store state in any data structure you like: plain objects, arrays, classes, cyclic data structures or references. It doesn't matter for the workings of MobX.
Just make sure that all properties you want to change over time are marked as `observable` so MobX can track them.
Here is a simple example:
```javascript
import { makeObservable, observable, action } from "mobx"
class Todo {
id = Math.random()
title = ""
finished = false
constructor(title) {
makeObservable(this, {
title: observable,
finished: observable,
toggle: action
})
this.title = title
}
toggle() {
this.finished = !this.finished
}
}
```
Using `observable` is like turning a property of an object into a spreadsheet cell.
But unlike spreadsheets, these values can not only be primitive values, but also references, objects and arrays.
Tip: Prefer classes, plain objects or decorators? MobX supports many styles.
This example can be shortened using [`makeAutoObservable`](observable-state.md), but by being explicit we can showcase the different concepts in greater detail.
Note that MobX doesn't dictate an object style, plain objects instead can be used as well, as can decorators for even more concise classes. See the page for more details.
But what about `toggle`, which we marked as `action`?
### 2. Update state using actions
An _action_ is any piece of code that changes the _state_. User events, backend data pushes, scheduled events, etc.
An action is like a user that enters a new value into a spreadsheet cell.
In the `Todo` model above you can see that we have a `toggle` method that changes the value of `finished`. `finished` is marked as `observable`. It is recommended that you mark any piece of code that changes `observable`'s as an [`action`](actions.md). That way MobX can automatically apply transactions for effortless optimal performance.
Using actions helps you structure your code and prevents you from inadvertently changing state when you don't intend to.
Methods that modify state are called _actions_ in MobX terminology. In contrast to _views_, which compute new information based on the current state.
Every method should serve at most one of those two goals.
### 3. Create derivations that automatically respond to state changes
_Anything_ that can be derived from the _state_ without any further interaction is a derivation.
Derivations exist in many forms:
- The _user interface_
- _Derived data_, such as the number of remaining `todos`
- _Backend integrations_, e.g. sending changes to the server
MobX distinguishes between two kinds of derivations:
- _Computed values_, which can always be derived from the current observable state using a pure function
- _Reactions_, side effects that need to happen automatically when the state changes (bridge between imperative and reactive programming)
When starting with MobX, people tend to overuse reactions.
The golden rule is, always use `computed` if you want to create a value based on the current state.
#### 3.1. Model derived values using computed
To create a _computed_ value, define a property using a JS getter function `get` and mark it as `computed` with `makeObservable`.
```javascript
import { makeObservable, observable, computed } from "mobx"
class TodoList {
todos = []
get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length
}
constructor(todos) {
makeObservable(this, {
todos: observable,
unfinishedTodoCount: computed
})
this.todos = todos
}
}
```
MobX will ensure that `unfinishedTodoCount` is updated automatically when a todo is added or when one of the `finished` properties is modified.
These computations resemble formulas in spreadsheet programs like MS Excel. They update automatically, but only when required. That is, if something is interested in their outcome.
#### 3.2. Model side effects using reactions
For you as a user to be able to see a change in state or computed values on the screen, a _reaction_ that repaints a part of the GUI is needed.
Reactions are similar to computed values, but instead of producing information, they produce side effects like printing to the console, making network requests, incrementally updating React component tree to patch the DOM, etc.
In short, reactions bridge the worlds of [reactive](https://en.wikipedia.org/wiki/Reactive_programming) and [imperative](https://en.wikipedia.org/wiki/Imperative_programming) programming.
By far the most used form of reactions are UI components.
Note that it is possible to trigger side effects from both actions and reactions.
Side effects that have a clear, explicit origin from which they can be triggered, such
as making a network request when submitting a form, should be triggered explicitly from the relevant event handler.
#### 3.3. Reactive React components
If you are using React, you can make your components reactive by wrapping them with the [`observer`](react-integration.md) function from the bindings package you've [chosen during installation](installation.md#installation). In this example, we're going to use the more lightweight `mobx-react-lite` package.
```javascript
import * as React from "react"
import { render } from "react-dom"
import { observer } from "mobx-react-lite"
const TodoListView = observer(({ todoList }) => (
{todoList.todos.map(todo => (
))}
Tasks left: {todoList.unfinishedTodoCount}
))
const TodoView = observer(({ todo }) => (
todo.toggle()} />
{todo.title}
))
const store = new TodoList([new Todo("Get Coffee"), new Todo("Write simpler code")])
render(, document.getElementById("root"))
```
`observer` converts React components into derivations of the data they render.
When using MobX there are no smart or dumb components.
All components render smartly, but are defined in a dumb manner. MobX will simply make sure the components are always re-rendered whenever needed, and never more than that.
So the `onClick` handler in the above example will force the proper `TodoView` component to re-render as it uses the `toggle` action, but will only cause the `TodoListView` component to re-render if the number of unfinished tasks has changed.
And if you would remove the `Tasks left` line (or put it into a separate component), the `TodoListView` component would no longer re-render when ticking a task.
To learn more about how React works with MobX, check out the [React integration](react-integration.md) section.
#### 3.4. Custom reactions
You will need them rarely, but they can be created using the [`autorun`](reactions.md#autorun),
[`reaction`](reactions.md#reaction) or [`when`](reactions.md#when) functions to fit your specific situations.
For example, the following `autorun` prints a log message every time the amount of `unfinishedTodoCount` changes:
```javascript
// A function that automatically observes the state.
autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount)
})
```
Why does a new message get printed every time the `unfinishedTodoCount` is changed? The answer is this rule of thumb:
_MobX reacts to any existing observable property that is read during the execution of a tracked function._
To learn more about how MobX determines which observables need to be reacted to, check out the [Understanding reactivity](understanding-reactivity.md) section.
## Principles
MobX uses a uni-directional data flow where _actions_ change the _state_, which in turn updates all affected _views_.

1. All _derivations_ are updated **automatically** and **atomically** when the _state_ changes. As a result, it is never possible to observe intermediate values.
2. All _derivations_ are updated **synchronously** by default. This means that, for example, _actions_ can safely inspect a computed value directly after altering the _state_.
3. _Computed values_ are updated **lazily**. Any computed value that is not actively in use will not be updated until it is needed for a side effect (I/O).
If a view is no longer in use it will be garbage collected automatically.
4. All _computed values_ should be **pure**. They are not supposed to change _state_.
To learn more about the background context, check out [the fundamental principles behind MobX](https://hackernoon.com/the-fundamental-principles-behind-mobx-7a725f71f3e8).
## Try it out!
You can play with the above examples yourself on [CodeSandbox](https://codesandbox.io/s/concepts-principles-il8lt?file=/src/index.js:1161-1252).
## Linting
If you find it hard to adopt the mental model of MobX, configure it to be very strict and warn you at runtime whenever you deviate from these patterns. Check out the [linting MobX](configuration.md#linting-options) section.
---
---
title: Understanding reactivity
sidebar_label: Understanding reactivity
hide_title: true
---
# Understanding reactivity
MobX usually reacts to exactly the things you expect it to, which means that in 90% of your use cases MobX should "just work".
However, at some point you will encounter a case where it does not do what you expected.
At that point it is invaluable to understand how MobX determines what to react to.
> MobX reacts to any _existing_ **observable** _property_ that is read during the execution of a tracked function.
- _"reading"_ is dereferencing an object's property, which can be done through "dotting into" it (eg. `user.name`) or using the bracket notation (eg. `user['name']`, `todos[3]`) or destructuring (eg. `const {name} = user`).
- _"tracked functions"_ are the expression of `computed`, the _rendering_ of an `observer` React function component, the `render()` method of an `observer` based React class component, and the functions that are passed as the first param to `autorun`, `reaction` and `when`.
- _"during"_ means that only those observables that are read while the function is executing are tracked. It doesn't matter whether these values are used directly or indirectly by the tracked function. But things that have been 'spawned' from the function won't be tracked (e.g. `setTimeout`, `promise.then`, `await` etc).
In other words, MobX will not react to:
- Values that are obtained from observables, but outside a tracked function
- Observables that are read in an asynchronously invoked code block
## MobX tracks property access, not values
To elaborate on the above rules with an example, suppose that you have the following observable instance:
```javascript
class Message {
title
author
likes
constructor(title, author, likes) {
makeAutoObservable(this)
this.title = title
this.author = author
this.likes = likes
}
updateTitle(title) {
this.title = title
}
}
let message = new Message("Foo", { name: "Michel" }, ["Joe", "Sara"])
```
In memory this looks as follows. The green boxes indicate _observable_ properties. Note that the _values_ themselves are not observable!

What MobX basically does is recording which _arrows_ you use in your function. After that, it will re-run whenever one of these _arrows_ changes; when they start to refer to something else.
## Examples
Let's show that with a bunch of examples (based on the `message` variable defined above):
#### Correct: dereference inside the tracked function
```javascript
autorun(() => {
console.log(message.title)
})
message.updateTitle("Bar")
```
This will react as expected. The `.title` property was dereferenced by the autorun, and changed afterwards, so this change is detected.
You can verify what MobX will track by calling [`trace()`](analyzing-reactivity.md) inside the tracked function. In the case of the above function it outputs the following:
```javascript
import { trace } from "mobx"
const disposer = autorun(() => {
console.log(message.title)
trace()
})
// Outputs:
// [mobx.trace] 'Autorun@2' tracing enabled
message.updateTitle("Hello")
// Outputs:
// [mobx.trace] 'Autorun@2' is invalidated due to a change in: 'Message@1.title'
Hello
```
It is also possible to get the internal dependency (or observer) tree by using `getDependencyTree`:
```javascript
import { getDependencyTree } from "mobx"
// Prints the dependency tree of the reaction coupled to the disposer.
console.log(getDependencyTree(disposer))
// Outputs:
// { name: 'Autorun@2', dependencies: [ { name: 'Message@1.title' } ] }
```
#### Incorrect: changing a non-observable reference
```javascript
autorun(() => {
console.log(message.title)
})
message = new Message("Bar", { name: "Martijn" }, ["Felicia", "Marcus"])
```
This will **not** react. `message` was changed, but `message` is not an observable, just a variable which _refers to_ an observable, but the variable (reference) itself is not observable.
#### Incorrect: dereference outside of a tracked function
```javascript
let title = message.title
autorun(() => {
console.log(title)
})
message.updateMessage("Bar")
```
This will **not** react. `message.title` was dereferenced outside of `autorun`, and just contains the value of `message.title` at the moment of dereferencing (the string `"Foo"`). `title` is not an observable so `autorun` will never react.
#### Correct: dereference inside the tracked function
```javascript
autorun(() => {
console.log(message.author.name)
})
runInAction(() => {
message.author.name = "Sara"
})
runInAction(() => {
message.author = { name: "Joe" }
})
```
This reacts to both changes. Both `author` and `author.name` are dotted into, allowing MobX to track these references.
Note that we had to use `runInAction` here to be allowed to make changes outside
of an `action`.
#### Incorrect: store a local reference to an observable object without tracking
```javascript
const author = message.author
autorun(() => {
console.log(author.name)
})
runInAction(() => {
message.author.name = "Sara"
})
runInAction(() => {
message.author = { name: "Joe" }
})
```
The first change will be picked up, `message.author` and `author` are the same object, and the `.name` property is dereferenced in the autorun.
However, the second change is **not** picked up, because the `message.author` relation is not tracked by the `autorun`. Autorun is still using the "old" `author`.
#### Common pitfall: console.log
```javascript
autorun(() => {
console.log(message)
})
// Won't trigger a re-run.
message.updateTitle("Hello world")
```
In the above example, the updated message title won't be printed, because it is not used inside the autorun.
The autorun only depends on `message`, which is not an observable, but a variable. In other words, as far as MobX is concerned, `title` is not used in the `autorun`.
If you use this in a web browser debugging tool, you may be able to find the
updated value of `title` after all, but this is misleading -- autorun run after all has run once when it was first called. This happens because `console.log` is an asynchronous function and the object is only formatted later in time. This means that if you follow the title in the debugging toolbar, you can find the updated value. But the `autorun` does not track any updates.
The way to make this work is to make sure to always pass immutable data or defensive copies to `console.log`. So the following solutions all react to changes in `message.title`:
```javascript
autorun(() => {
console.log(message.title) // Clearly, the `.title` observable is used.
})
autorun(() => {
console.log(mobx.toJS(message)) // toJS creates a deep clone, and thus will read the message.
})
autorun(() => {
console.log({ ...message }) // Creates a shallow clone, also using `.title` in the process.
})
autorun(() => {
console.log(JSON.stringify(message)) // Also reads the entire structure.
})
```
#### Correct: access array properties in tracked function
```javascript
autorun(() => {
console.log(message.likes.length)
})
message.likes.push("Jennifer")
```
This will react as expected. `.length` counts towards a property.
Note that this will react to _any_ change in the array.
Arrays are not tracked per index / property (like observable objects and maps), but as a whole.
#### Incorrect: access out-of-bounds indices in tracked function
```javascript
autorun(() => {
console.log(message.likes[0])
})
message.likes.push("Jennifer")
```
This will react with the above sample data because array indexes count as property access. But **only** if the provided `index < length`.
MobX does not track not-yet-existing array indices.
So always guard your array index based access with a `.length` check.
#### Correct: access array functions in tracked function
```javascript
autorun(() => {
console.log(message.likes.join(", "))
})
message.likes.push("Jennifer")
```
This will react as expected. All array functions that do not mutate the array are tracked automatically.
---
```javascript
autorun(() => {
console.log(message.likes.join(", "))
})
message.likes[2] = "Jennifer"
```
This will react as expected. All array index assignments are detected, but only if `index <= length`.
#### Incorrect: "use" an observable but without accessing any of its properties
```javascript
autorun(() => {
message.likes
})
message.likes.push("Jennifer")
```
This will **not** react. Simply because the `likes` array itself is not being used by the `autorun`, only the reference to the array.
So in contrast, `message.likes = ["Jennifer"]` would be picked up; that statement does not modify the array, but the `likes` property itself.
#### Correct: using not yet existing map entries
```javascript
const twitterUrls = observable.map({
Joe: "twitter.com/joey"
})
autorun(() => {
console.log(twitterUrls.get("Sara"))
})
runInAction(() => {
twitterUrls.set("Sara", "twitter.com/horsejs")
})
```
This **will** react. Observable maps support observing entries that may not exist.
Note that this will initially print `undefined`.
You can check for the existence of an entry first by using `twitterUrls.has("Sara")`.
So in an environment without Proxy support for dynamically keyed collections always use observable maps. If you do have Proxy support you can use observable maps as well,
but you also have the option to use plain objects.
#### MobX does not track asynchronously accessed data
```javascript
function upperCaseAuthorName(author) {
const baseName = author.name
return baseName.toUpperCase()
}
autorun(() => {
console.log(upperCaseAuthorName(message.author))
})
runInAction(() => {
message.author.name = "Chesterton"
})
```
This will react. Even though `author.name` is not dereferenced by the function passed to `autorun` itself, MobX will still track the dereferencing that happens in `upperCaseAuthorName`, because it happens _during_ the execution of the autorun.
---
```javascript
autorun(() => {
setTimeout(() => console.log(message.likes.join(", ")), 10)
})
runInAction(() => {
message.likes.push("Jennifer")
})
```
This will **not** react because during the execution of the `autorun` no observables were accessed, only during the `setTimeout`, which is an asynchronous function.
Check out the [Asynchronous actions](actions.md#asynchronous-actions) section as well.
#### Using non-observable object properties
```javascript
autorun(() => {
console.log(message.author.age)
})
runInAction(() => {
message.author.age = 10
})
```
This **will** react if you run React in an environment that supports Proxy.
Note that this is only done for objects created with `observable` or `observable.object`. New properties on class instances will not be made observable automatically.
_Environments without Proxy support_
This will **not** react. MobX can only track observable properties, and 'age' has not been defined as observable property above.
However, it is possible to use the `get` and `set` methods as exposed by MobX to work around this:
```javascript
import { get, set } from "mobx"
autorun(() => {
console.log(get(message.author, "age"))
})
set(message.author, "age", 10)
```
#### [Without Proxy support] Incorrect: using not yet existing observable object properties
```javascript
autorun(() => {
console.log(message.author.age)
})
extendObservable(message.author, {
age: 10
})
```
This will **not** react. MobX will not react to observable properties that did not exist when tracking started.
If the two statements are swapped, or if any other observable causes the `autorun` to re-run, the `autorun` will start tracking the `age` as well.
#### [Without Proxy support] Correct: using MobX utilities to read / write to objects
If you are in an environment without proxy support and still want to use observable
objects as a dynamic collection, you can handle them using the MobX `get` and `set`
API.
The following will react as well:
```javascript
import { get, set, observable } from "mobx"
const twitterUrls = observable.object({
Joe: "twitter.com/joey"
})
autorun(() => {
console.log(get(twitterUrls, "Sara")) // `get` can track not yet existing properties.
})
runInAction(() => {
set(twitterUrls, { Sara: "twitter.com/horsejs" })
})
```
Check out the [Collection utilities API](api.md#collection-utilities-) for more details.
#### TL;DR
> MobX reacts to any _existing_ **observable** _property_ that is read during the execution of a tracked function.