Simple, scalable state management.
npm install @dannsam/mobx
npm install mobx --save. React bindings: npm install mobx-react --save. To enable ESNext decorators (optional), see below.
javascript
class Todo {
id = Math.random();
@observable title = "";
@observable finished = false;
}
`
Using observable is like turning a property of an object into a spreadsheet cell.
But unlike spreadsheets, these values can be not only primitive values, but also references, objects and arrays.
You can even define your own observable data sources.
$3
If these @ thingies look alien to you, these are ES.next decorators.
Using them is entirely optional in MobX. See the documentation for details how to either use or avoid them.
MobX runs on any ES5 environment, but leveraging ES.next features like decorators are the cherry on the pie when using MobX.
The remainder of this readme uses decorators, but remember, _they are optional_.
For example, in good ol' ES5 the above snippet would look like:
`javascript
function Todo() {
this.id = Math.random()
extendObservable(this, {
title: "",
finished: false
})
}
`
$3
Egghead.io lesson 3: computed values
With MobX you can define values that will be derived automatically when relevant data is modified.
By using the @computed decorator or by using getter / setter functions when using (extend)Observable.
`javascript
class TodoList {
@observable todos = [];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
`
MobX will ensure that unfinishedTodoCount is updated automatically when a todo is added or when one of the finished properties is modified.
Computations like these resemble formulas in spreadsheet programs like MS Excel. They update automatically and only when required.
$3
Egghead.io lesson 9: custom reactions
Reactions are similar to a computed value, but instead of producing a new value, a reaction produces a side effect for things like printing to the console, making network requests, incrementally updating the React component tree to patch the DOM, etc.
In short, reactions bridge reactive and imperative programming.
#### React components
Egghead.io lesson 1: observable & observer
If you are using React, you can turn your (stateless function) components into reactive components by simply adding the observer function / decorator from the mobx-react package onto them.
`javascript
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {observer} from 'mobx-react';
@observer
class TodoListView extends Component {
render() {
return
{this.props.todoList.todos.map(todo =>
)}
Tasks left: {this.props.todoList.unfinishedTodoCount}
}
}
const TodoView = observer(({todo}) =>
type="checkbox"
checked={todo.finished}
onClick={() => todo.finished = !todo.finished}
/>{todo.title}
)
const store = new TodoList();
ReactDOM.render( , document.getElementById('mount'));
`
observer turns React (function) 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, but also no more than that. So the onClick handler in the above example will force the proper TodoView to render, and it will cause the TodoListView to render if the number of unfinished tasks has changed.
However, if you would remove the Tasks left line (or put it into a separate component), the TodoListView will no longer re-render when ticking a box. You can verify this yourself by changing the JSFiddle.
#### Custom reactions
Custom reactions can simply be created using the autorun,
reaction or when functions to fit your specific situations.
For example the following autorun prints a log message each time the amount of unfinishedTodoCount changes:
`javascript
autorun(() => {
console.log("Tasks left: " + todos.unfinishedTodoCount)
})
`
$3
Why does a new message get printed each 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._
For an in-depth explanation about how MobX determines to which observables needs to be reacted, check understanding what MobX reacts to.
$3
Egghead.io lesson 5: actions
Unlike many flux frameworks, MobX is unopinionated about how user events should be handled.
* This can be done in a Flux like manner.
* Or by processing events using RxJS.
* Or by simply handling events in the most straightforward way possible, as demonstrated in the above onClick handler.
In the end it all boils down to: Somehow the state should be updated.
After updating the state MobX will take care of the rest in an efficient, glitch-free manner. So simple statements, like below, are enough to automatically update the user interface.
There is no technical need for firing events, calling a dispatcher or what more. A React component in the end is nothing more than a fancy representation of your state. A derivation that will be managed by MobX.
`javascript
store.todos.push(
new Todo("Get Coffee"),
new Todo("Write simpler code")
);
store.todos[0].finished = true;
`
Nonetheless, MobX has an optional built-in concept of actions.
Use them to your advantage; they will help you to structure your code better and make wise decisions about when and where state should be modified.
MobX: Simple and scalable
MobX is one of the least obtrusive libraries you can use for state management. That makes the MobX approach not just simple, but very scalable as well:
$3
With MobX you don't need to normalize your data. This makes the library very suitable for very complex domain models (At Mendix for example ~500 different domain classes in a single application).
$3
Since data doesn't need to be normalized, and MobX automatically tracks the relations between state and derivations, you get referential integrity for free. Rendering something that is accessed through three levels of indirection?
No problem, MobX will track them and re-render whenever one of the references changes. As a result staleness bugs are a thing of the past. As a programmer you might forget that changing some data might influence a seemingly unrelated component in a corner case. MobX won't forget.
$3
As demonstrated above, modifying state when using MobX is very straightforward. You simply write down your intentions. MobX will take care of the rest.
$3
MobX builds a graph of all the derivations in your application to find the least number of re-computations that is needed to prevent staleness. "Derive everything" might sound expensive, MobX builds a virtual derivation graph to minimize the number of recomputations needed to keep derivations in sync with the state.
In fact, when testing MobX at Mendix we found out that using this library to track the relations in our code is often a lot more efficient then pushing changes through our application by using handwritten events or "smart" selector based container components.
The simple reason is that MobX will establish far more fine grained 'listeners' on your data then you would do as a programmer.
Secondly MobX sees the causality between derivations so it can order them in such a way that no derivation has to run twice or introduces a glitch.
How that works? See this in-depth explanation of MobX.
$3
MobX works with plain javascript structures. Due to its unobtrusiveness it works with most javascript libraries out of the box, without needing MobX specific library flavors.
So you can simply keep using your existing router, data fetching, and utility libraries like react-router, director, superagent, lodash etc.
For the same reason you can use it out of the box both server and client side, in isomorphic applications and with react-native.
The result of this is that you often need to learn less new concepts when using MobX in comparison to other state management solutions.
---
__MobX is proudly used in mission critical systems at Mendix__
Credits
MobX is inspired by reactive programming principles as found in spreadsheets. It is inspired by MVVM frameworks like in MeteorJS tracker, knockout and Vue.js. But MobX brings Transparent Functional Reactive Programming to the next level and provides a stand alone implementation. It implements TFRP in a glitch-free, synchronous, predictable and efficient manner.
A ton of credits for Mendix, for providing the flexibility and support to maintain MobX and the chance to proof the philosophy of MobX in a real, complex, performance critical applications.
And finally kudos for all the people that believed in, tried, validated and even sponsored MobX.
Further resources and documentation
* MobX homepage
* API overview
* Tutorials, Blogs & Videos
* Boilerplates
* Related projects
What others are saying...
> Guise, #mobx isn't pubsub, or your grandpa's observer pattern. Nay, it is a carefully orchestrated observable dimensional portal fueled by the power cosmic. It doesn't do change detection, it's actually a level 20 psionic with soul knife, slashing your viewmodel into submission.
> After using #mobx for lone projects for a few weeks, it feels awesome to introduce it to the team. Time: 1/2, Fun: 2X
> Working with #mobx is basically a continuous loop of me going “this is way too simple, it definitely won’t work” only to be proven wrong
> Try react-mobx with es6 and you will love it so much that you will hug someone.
> I have built big apps with MobX already and comparing to the one before that which was using Redux, it is simpler to read and much easier to reason about.
> The #mobx is the way I always want things to be! It's really surprising simple and fast! Totally awesome! Don't miss it!
Contributing
* Feel free to send small pull requests. Please discuss new features or big changes in a GitHub issue first.
* Use npm test to run the basic test suite, npm run coverage for the test suite with coverage and npm run perf for the performance tests.
Flow support
MobX ships with flow typings. To use them in your project, add this to the [libs] section of your .flowconfig:
`
[libs]
node_modules/mobx/lib/mobx.js.flow
`
Bower support
Bower support is available through the infamous unpkg.com:
bower install https://unpkg.com/mobx/bower.zip
Then use lib/mobx.umd.js or lib/mobx.umd.min.js
MobX was formerly known as Mobservable.
See the changelog for all the details about mobservable to mobx`.