Skip to content

Commit 1709b48

Browse files
committed
Updated readme with getter syntax and less ES.next. See also facebook/create-react-app#410
1 parent 3abe0e6 commit 1709b48

File tree

1 file changed

+180
-90
lines changed

1 file changed

+180
-90
lines changed

README.md

Lines changed: 180 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ _Simple, scalable state management_
1010
![npm install mobx](https://nodei.co/npm/mobx.png?downloadRank=true&downloads=true)
1111

1212
* Installation: `npm install mobx --save`. React bindings: `npm install mobx-react --save`. To enable ESNext decorators (optional), see below.
13+
* CDN: https://unpkg.com/mobx/lib/mobx.umd.js
14+
15+
## Getting started
16+
1317
* [Ten minute, interactive MobX + React tutorial](https://mobxjs.github.io/mobx/getting-started.html)
1418
* [Official documentation and API overview](https://mobxjs.github.io/mobx/refguide/api.html)
1519
* Videos:
1620
* [Egghead.io course: Manage Complex State in React Apps with MobX](https://egghead.io/courses/manage-complex-state-in-react-apps-with-mobx) - 30m.
1721
* [Practical React with MobX](https://www.youtube.com/watch?v=XGwuM_u7UeQ). In depth introduction and explanation to MobX and React by Matt Ruby on OpenSourceNorth (ES5 only) - 42m.
1822
* LearnCode.academy MobX tutorial [Part I: MobX + React is AWESOME (7m)](https://www.youtube.com/watch?v=_q50BXqkAfI) [Part II: Computed Values and Nested/Referenced Observables (12m.)](https://www.youtube.com/watch?v=nYvNqKrl69s)
1923
* [Screencast: intro to MobX](https://www.youtube.com/watch?v=K8dr8BMU7-8) - 8m
20-
* [State Management Is Easy, React Amsterdam 2016 conf](https://www.youtube.com/watch?v=ApmSsu3qnf0&feature=youtu.be) ([slides](https://speakerdeck.com/mweststrate/state-management-is-easy-introduction-to-mobx))
21-
* [Magix MobX, RuhrJS 2016](https://www.youtube.com/watch?v=TfxfRkNCnmk)
22-
* [Transparent Reactive Programming and Mutable Data, Reactive2015 conf](https://www.youtube.com/watch?v=FEwLwiizlk0) ([slides](https://speakerdeck.com/mweststrate/react-transparent-reactive-programming-and-mutable-data-structures))
23-
* More tutorials, blogs and videos can be found on the [MobX homepage](http://mobxjs.github.io/mobx/faq/blogs.html)
24+
* [Talk: State Management Is Easy, React Amsterdam 2016 conf](https://www.youtube.com/watch?v=ApmSsu3qnf0&feature=youtu.be) ([slides](https://speakerdeck.com/mweststrate/state-management-is-easy-introduction-to-mobx))
2425
* [Boilerplates and related projects](http://mobxjs.github.io/mobx/faq/boilerplates.html)
26+
* More tutorials, blogs and videos can be found on the [MobX homepage](http://mobxjs.github.io/mobx/faq/blogs.html)
2527

2628

2729
## Introduction
@@ -45,74 +47,45 @@ MobX has only a few core concepts. The following snippets can be tried online us
4547

4648
### Observable state
4749

48-
MobX adds observable capabilities to existing data structures like objects, arrays and class instances. This can simply be done by annotating your class properties with the [@observable](http://mobxjs.github.io/mobx/refguide/observable-decorator.html) decorator (ES.Next), or by invoking the [`observable`](http://mobxjs.github.io/mobx/refguide/observable.html) or [`extendObservable`](http://mobxjs.github.io/mobx/refguide/extend-observable.html) functions (ES5). See [Language support](https://github.com/mobxjs/mobx/wiki/Language-Support) for language-specific examples.
50+
MobX adds observable capabilities to existing data structures like objects, arrays and class instances.
51+
This can simply be done by annotating your class properties with the [@observable](http://mobxjs.github.io/mobx/refguide/observable-decorator.html) decorator (ES.Next),
52+
or by invoking the [`observable`](http://mobxjs.github.io/mobx/refguide/observable.html) or [`extendObservable`](http://mobxjs.github.io/mobx/refguide/extend-observable.html) functions (ES5).
53+
Scroll down for more ES5 / ES6 and ES.next examples.
4954

5055
```javascript
51-
// ESNext class example with decorators:
52-
class Todo {
53-
id = Math.random();
54-
@observable title = "";
55-
@observable finished = false;
56-
}
57-
58-
// ES6 class without decorators:
59-
class Todo {
60-
constructor() {
61-
this.id = Math.random()
62-
extendObservable(this, {
63-
title: "",
64-
finished: false
65-
})
66-
}
67-
}
68-
69-
// ES5 constructor function example:
70-
function Todo() {
71-
this.id = Math.random()
72-
extendObservable(this, {
73-
title: "",
74-
finished: false
75-
})
76-
}
77-
78-
// ... or just create plain objects:
7956
function createTodo() {
8057
return observable({
8158
id: Math.random(),
8259
title: "",
8360
finished: false
8461
})
8562
}
86-
8763
```
8864

89-
Using `@observable` is like turning a value into a spreadsheet cell. But unlike spreadsheets, not only can these values be primitive values, but references, objects and arrays as well. You can even [define your own](http://mobxjs.github.io/mobx/refguide/extending.html) observable data sources.
65+
Using `observable` is like turning the properties of an object into a spreadsheet cells.
66+
But unlike spreadsheets, these values cannot just be primitive values, but also references, objects and arrays.
67+
You can even [define your own](http://mobxjs.github.io/mobx/refguide/extending.html) observable data sources.
9068

9169
### Computed values
9270

93-
With MobX you can define values that will be derived automatically when relevant data is modified. By using the [`@computed`](http://mobxjs.github.io/mobx/refguide/computed-decorator.html) decorator or by using parameterless functions as property values in `extendObservable`.
71+
With MobX you can define values that will be derived automatically when relevant data is modified.
72+
By using the [`@computed`](http://mobxjs.github.io/mobx/refguide/computed-decorator.html) decorator or by using getter / setter functions when using `(extend)Observable`.
9473

9574
```javascript
96-
// ESNext class example:
9775
class TodoList {
98-
@observable todos = [];
99-
@computed get unfinishedTodoCount() {
100-
return this.todos.filter(todo => !todo.finished).length;
101-
}
102-
}
103-
104-
// ES5 constructor function example:
105-
function TodoList() {
106-
extendObservable(this, {
107-
todos: [],
108-
unfinishedTodoCount: function() {
109-
return this.todos.filter(function (todo) {
110-
return !todo.finished
111-
}).length;
112-
}
113-
})
76+
constructor() {
77+
extendObservable(this, {
78+
todos: [],
79+
get unfinishedTodoCount() {
80+
return this.todos.filter(function (todo) {
81+
return !todo.finished
82+
}).length;
83+
}
84+
})
85+
}
11486
}
11587
```
88+
11689
MobX will ensure that `unfinishedTodoCount` is updated automatically when a todo is added or when one of the `finished` properties is modified.
11790
Computations like these can very well be compared with formulas in spreadsheet programs like MS Excel. They update automatically whenever, and only when, needed.
11891

@@ -121,16 +94,14 @@ Computations like these can very well be compared with formulas in spreadsheet p
12194
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.
12295
In short, reactions bridge [reactive](https://en.wikipedia.org/wiki/Reactive_programming) and [imperative](https://en.wikipedia.org/wiki/Imperative_programming) programming.
12396

124-
If you are using React, you can turn your (stateless function) components into reactive components by simply adding the [`@observer`](http://mobxjs.github.io/mobx/refguide/observer-component.html) decorator from the `mobx-react` package onto them.
97+
If you are using React, you can turn your (stateless function) components into reactive components by simply adding the [`observer`](http://mobxjs.github.io/mobx/refguide/observer-component.html) function / decorator from the `mobx-react` package onto them.
12598

12699
```javascript
127100
import React, {Component} from 'react';
128101
import ReactDOM from 'react-dom';
129102
import {observer} from "mobx-react";
130103

131-
// ESNext decorator / JSX
132-
@observer
133-
class TodoListView extends Component {
104+
const TodoListView = observer(class extends Component {
134105
render() {
135106
return <div>
136107
<ul>
@@ -141,7 +112,7 @@ class TodoListView extends Component {
141112
Tasks left: {this.props.todoList.unfinishedTodoCount}
142113
</div>
143114
}
144-
}
115+
})
145116

146117
const TodoView = observer(({todo}) =>
147118
<li>
@@ -151,27 +122,20 @@ const TodoView = observer(({todo}) =>
151122
onClick={() => todo.finished = !todo.finished}
152123
/>{todo.title}
153124
</li>
154-
);
125+
)
155126

156127
const store = new TodoList();
157128
ReactDOM.render(<TodoListView todoList={store} />, document.getElementById('mount'));
158129
```
159130

160-
In ES5 a component declaration looks like this:
161-
```javascript
162-
var TodoListView = observer(React.createClass({ /* etc */ }))
163-
```
164-
165131
`observer` turns React (function) components into derivations of the data they render.
166-
167-
Also, reactions can be created using the [`autorun`](http://mobxjs.github.io/mobx/refguide/autorun.html), [`autorunAsync`](http://mobxjs.github.io/mobx/refguide/autorun-async.html) or [`when`](http://mobxjs.github.io/mobx/refguide/when.html) functions to fit your specific situations.
168-
169132
When using MobX there are no smart or dumb components.
170-
171133
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.
172-
173134
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](https://jsfiddle.net/mweststrate/wv3yopo0/).
174135

136+
Custom reactions can simply be created using the [`autorun`](http://mobxjs.github.io/mobx/refguide/autorun.html),
137+
[`autorunAsync`](http://mobxjs.github.io/mobx/refguide/autorun-async.html) or [`when`](http://mobxjs.github.io/mobx/refguide/when.html) functions to fit your specific situations.
138+
175139
For an in-depth explanation about how MobX determines to which observables needs to be reacted, check out: [Understanding what MobX reacts to](https://github.com/mobxjs/mobx/blob/gh-pages/docs/best/react.md)
176140

177141
### Actions
@@ -199,6 +163,153 @@ store.todos[0].finished = true;
199163
Nonetheless, MobX has an optional built-in concept of [`actions`](https://mobxjs.github.io/mobx/refguide/action.html).
200164
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.
201165

166+
## Using MobX in ES5, ES6 and ES.next environments
167+
168+
MobX runs on any ES5 environment. Depending on your project setup, you can leverage ES6 and even ES.next features like decorators to make
169+
working with MobX a really joyful experience. Decorators can be transpiled by both TypeScript and Babel with a little configuration,
170+
[see below](#enabling-decorators-optional)
171+
172+
### Creating observables
173+
174+
The simplest way to create an observable object in ES5 is by taking a plain object and turning it into an observable object using `observable`:
175+
176+
```javascript
177+
var timer = observable({
178+
// observables
179+
start: Date.now(),
180+
current: Date.now(),
181+
// computed property
182+
get elapsedTime() {
183+
return (this.current - this.start) + "seconds"
184+
},
185+
// action
186+
tick: action(function() {
187+
this.current = Date.now()
188+
})
189+
})
190+
```
191+
192+
Similarly, you can create a constructor function easily as well:
193+
194+
```javascript
195+
function Timer() {
196+
extendObservable(this, {
197+
start: Date.now(),
198+
current: Date.now(),
199+
get elapsedTime() {
200+
return (this.current - this.start) + "seconds"
201+
}
202+
})
203+
}
204+
Timer.prototype.tick = action(function() {
205+
this.current = Date.now()
206+
})
207+
208+
var timer = new Timer()
209+
```
210+
211+
Using ES6 classes is quite similar:
212+
213+
```javascript
214+
class Timer {
215+
constructor() {
216+
extendObservable(this, {
217+
start: Date.now(),
218+
current: Date.now(),
219+
get elapsedTime() {
220+
return (this.current - this.start) + "seconds"
221+
}
222+
})
223+
}
224+
}
225+
Timer.prototype.tick = action(function() {
226+
this.current = Date.now()
227+
})
228+
229+
const timer = new Timer()
230+
```
231+
232+
ES.next decorators in combination with field initializers can turn the above into some really nice declarative code:
233+
234+
```javascript
235+
class Timer {
236+
@observabe start = Date.now();
237+
@observable current = Date.now();
238+
239+
@computed get elapsedTime() {
240+
return (this.current - this.start) + "seconds"
241+
}
242+
243+
@action tick() {
244+
this.current = Date.now()
245+
}
246+
}
247+
248+
const timer = new Timer()
249+
```
250+
251+
## Creating `observer` components
252+
253+
Similarly, the `observer` function / decorator from the `"mobx-react"` package can be applied in different ways.
254+
With stateless function components `observer` should always be invoked as function:
255+
256+
```javascript
257+
const Timer = observer(function(props) {
258+
return React.createElement("div", {}, props.timer.elapsedTime)
259+
})
260+
```
261+
262+
Or, with ES6:
263+
264+
```javascript
265+
const Timer = observer(({ timer }) =>
266+
<div>{ props.timer.elapsedTime }</div>
267+
)
268+
```
269+
270+
Similarly, classes (either ES6 or created using `React.createClass` can be passed through `observer`:
271+
272+
```javascript
273+
const Timer = observer(React.createClass({
274+
/* ... */
275+
}))
276+
277+
const Timer = observer(class Timer extends React.Component {
278+
/* ... */
279+
})
280+
```
281+
282+
Finally, `@observer` can be used as decorator in ES.next / Typescript if decorators are enabled:
283+
284+
```javascript
285+
@observer
286+
class Timer extends React.Component {
287+
/* ... */
288+
}
289+
```
290+
291+
### Enabling decorators (optional)
292+
293+
**TypeScript**
294+
295+
Enable the compiler option `experimentalDecorators` in `tsconfig.json` or pass it as flag `--experimentalDecorators` to the compiler.
296+
297+
**Babel:**
298+
299+
Install support for decorators: `npm i --save-dev babel-plugin-transform-decorators-legacy`. And enable it in your `.babelrc` file:
300+
301+
```
302+
{
303+
"presets": [
304+
"es2015",
305+
"stage-1"
306+
],
307+
"plugins": ["transform-decorators-legacy"]
308+
}
309+
```
310+
311+
Note that the order is important and `transform-decorators-legacy` should be listed *first*.
312+
202313
## MobX: Simple and scalable
203314

204315
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:
@@ -283,27 +394,6 @@ And finally kudo's for all the people that believed in, tried, validated and eve
283394
* Feel free to send small pull requests. Please discuss new features or big changes in a GitHub issue first.
284395
* 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.
285396

286-
## Enabling decorators (optional)
287-
288-
**TypeScript**
289-
290-
Enable the compiler option `experimentalDecorators` in `tsconfig.json` or pass it as flag `--experimentalDecorators` to the compiler.
291-
292-
**Babel:**
293-
294-
Install support for decorators: `npm i --save-dev babel-plugin-transform-decorators-legacy`. And enable it in your `babelrc` file:
295-
296-
```
297-
{
298-
"presets": [
299-
"es2015",
300-
"stage-1"
301-
],
302-
"plugins": ["transform-decorators-legacy"]
303-
}
304-
```
305-
Probably you have more plugins and presets in your `.babelrc` already, note that the order is important and `transform-decorators-legacy` should come as first.
306-
307397
## Bower support
308398

309399
Bower support is available through the infamous npmcdn.com:

0 commit comments

Comments
 (0)