-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update docs to mobx 3 #725
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,12 @@ | |
Usage: | ||
* `action(fn)` | ||
* `action(name, fn)` | ||
* `@action classMethod` | ||
* `@action(name) classMethod` | ||
* `@action classMethod() {}` | ||
* `@action(name) classMethod () {}` | ||
* `@action boundClassMethod = (args) => { body }` | ||
* `@action(name) boundClassMethod = (args) => { body }` | ||
* `@action.bound classMethod() {}` | ||
* `@action.bound(function() {}) | ||
|
||
Any application has actions. Actions are anything that modify the state. | ||
With MobX you can make it explicit in your code where your actions live by marking them. | ||
|
@@ -68,3 +70,40 @@ Example: | |
The usage of `runInAction` is: `runInAction(name?, fn, scope?)`. | ||
|
||
If you use babel, this plugin could help you to handle your async actions: [mobx-deep-action](https://github.com/mobxjs/babel-plugin-mobx-deep-action). | ||
|
||
## Bound actions | ||
|
||
The `action` decorator / function follows the normal rules for binding in javascript. | ||
However, Mobx 3 introduces `action.bound` to automatically bind actions to the targeted object. | ||
Note that `(@)action.bound` does, unlike `action`, not take a name parameter, the name will always be based on the property the action is bound to. | ||
|
||
Example: | ||
|
||
```javascript | ||
class Ticker { | ||
@observable this.tick = 0 | ||
|
||
@action.bound | ||
increment() { | ||
this.tick++ // 'this' will always be correct | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please explain why this might not be correct using plain |
||
} | ||
} | ||
|
||
const ticker = new Ticker() | ||
setInterval(ticker.increment, 1000) | ||
``` | ||
|
||
Or | ||
|
||
```javascript | ||
const ticker = observable({ | ||
tick: 1, | ||
increment: action.bound(function() { | ||
this.tick++ // bound 'this' | ||
}) | ||
}) | ||
|
||
setInterval(ticker.increment, 1000) | ||
``` | ||
|
||
_Note: don't use *action.bind* with arrow functions; arrow functions are already bound and cannot be rebound._ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo: should say |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,46 +1,129 @@ | ||
# MobX Api Reference | ||
|
||
Applies to MobX 3 and higher. For MobX 2, the old documentation is still available on [githib](https://github.com/mobxjs/mobx/blob/7c9e7c86e0c6ead141bb0539d33143d0e1f576dd/docs/refguide/api.md) | ||
|
||
# Core API | ||
|
||
_The most important MobX api's. Understanding `observable`, `computed`, `reactions` and `actions` is enough to master MobX and use it in your applications!_ | ||
|
||
## Creating observables | ||
|
||
### `observable` | ||
|
||
### `observable(value)` | ||
Usage: | ||
* `observable(value)` | ||
* `@observable classProperty = value` | ||
|
||
Observable values can be JS primitives, references, plain objects, class instances, arrays and maps. | ||
`observable(value)` is a convenience overload, that always tries to create the best matching observable types. | ||
You can also directly create the desired observable type, see below. | ||
|
||
The following conversion rules are applied, but can be fine-tuned by using *modifiers*. See below. | ||
|
||
1. If *value* is wrapped in the *modifier* `asMap`: a new [Observable Map](map.md) will be returned. Observable maps are very useful if you don't want to react just to the change of a specific entry, but also to the addition or removal of entries. | ||
1. If *value* is an wrapped is an instance of an [ES6 Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map): a new [Observable Map](map.md) will be returned. Observable maps are very useful if you don't want to react just to the change of a specific entry, but also to the addition or removal of entries. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
should probably be
|
||
1. If *value* is an array, a new [Observable Array](array.md) will be returned. | ||
1. If *value* is an object *without* prototype, all its current properties will be made observable. See [Observable Object](object.md) | ||
1. If *value* is an object *without* prototype, the object will be cloned and all its current properties will be made observable. See [Observable Object](object.md) | ||
1. If *value* is an object *with* a prototype, a JavaScript primitive or function, a [Boxed Observable](boxed.md) will be returned. MobX will not make objects with a prototype automatically observable; as that is the responsibility of it's constructor function. Use `extendObservable` in the constructor, or `@observable` in it's class definition instead. | ||
|
||
These rules might seem complicated at first sight, but you will notice that in practice they are very intuitive to work with. | ||
Some notes: | ||
* To create dynamically keyed objects use the `asMap` modifier! Only initially existing properties on an object will be made observable, although new ones can be added using `extendObservable`. | ||
* To create dynamically keyed objects always use maps! Only initially existing properties on an object will be made observable, although new ones can be added using `extendObservable`. | ||
* To use the `@observable` decorator, make sure that [decorators are enabled](http://mobxjs.github.io/mobx/refguide/observable-decorator.html) in your transpiler (babel or typescript). | ||
* By default making a data structure observable is *infective*; that means that `observable` is applied automatically to any value that is contained by the data structure, or will be contained by the data structure in the future. This behavior can be changed by using *modifiers*. | ||
* By default making a data structure observable is *infective*; that means that `observable` is applied automatically to any value that is contained by the data structure, or will be contained by the data structure in the future. This behavior can be changed by using *modifiers* or *shallow*. | ||
|
||
[«`observable`»](observable.md) — [«`@observable`»](observable-decorator.md) | ||
|
||
### `extendObservable` | ||
Usage: `extendObservable(target, propertyMap)`. For each key/value pair in `propertyMap` a (new) observable property will be introduced on the target object. | ||
### `@observable property = value` | ||
|
||
`observable` can also be used as property decorator. It requires [decorators to be enabled](../best/decorators.md) and is syntactic | ||
sugar for `extendObservable(this, { property: value })`. | ||
|
||
[«`details`»](observable-decorator.md) | ||
|
||
### `observable.box(value)` & `observable.shallowBox(value)` | ||
|
||
Creates an observable _box_ that stores an observable reference to a value. Use `get()` to get the current value of the box, and `set()` to update it. | ||
This is the foundation on which all other observables are built, but in practice you will use it rarely. | ||
Normal boxes will automatically try to turn any new value into an observable if it isn't already. Use `shallowBox` to disable this behavior. | ||
|
||
[«`details`»](boxed.md) | ||
|
||
### `observable.object(value)` & `observable.shallowObject(value)` | ||
|
||
Creates a clone of the provided object and makes all it's properties observable. | ||
By default any values in those properties will be made observable as well, but when using `shallowObject` only the properties will be made into observable | ||
references, but the values will be untouched. (This holds also for any values assigned in the future) | ||
|
||
[«`details`»](object.md) | ||
|
||
### `observable.array(value)` & `observable.shallowArray(value)` | ||
|
||
Creates a new observable array based on the provided value. Use `shallowArray` if the values in the array should not be turned into observables. | ||
|
||
[«`details`»](array.md) | ||
|
||
### `observable.map(value)` & `observable.shallowMap(value)` | ||
|
||
Creates a new observable map based on the provided value. Use `shallowMap` if the values in the array should not be turned into observables. | ||
Use `map` whenever you want to create a dynamically keyed collections and the addition / removal of keys needs to be observed. | ||
Note that only string keys are supported. | ||
|
||
[«`details`»](map.md) | ||
|
||
### `extendObservable` & `extendShallowObservable` | ||
Usage: `extendObservable(target, ...propertyMaps)`. For each key/value pair in each `propertyMap` a (new) observable property will be introduced on the target object. | ||
This can be used in constructor functions to introduce observable properties without using decorators. | ||
If a value of the `propertyMap` is an argumentless function, a *computed* property will be introduced. | ||
If a value of the `propertyMap` is a getter function, a *computed* property will be introduced. | ||
|
||
Use `extendShallowObservable` if the new properties should not be infective (that is; newly assigned values should not be turned into observables automatically). | ||
Note that `extendObservable` enhances existing objects, unlike `observable.object` which creates a new object. | ||
|
||
[«details»](extend-observable.md) | ||
|
||
### Modifiers | ||
|
||
Modifiers can be used decorator or in combination with `extendObservable` and `observable.object` to change the autoconversion rules for specific properties. | ||
|
||
The following modifiers are available: | ||
|
||
* `observable.deep`: This is the default modifier, used by any observable. It converts any assigned, non-primitive value into an observable if it isn't one yet. | ||
* `observable.ref`: Disables automatic observable conversion, just creates an observable reference instead. | ||
* `observable.shallow`: Can only used in combination with collections. Turns any assigned collection into an collection, which is shallowly observable (instead of deep). In other words; the values inside the collection won't become observables automatically. | ||
* `computed`: Creates a derived property, see [`computed`](computed-decorator.md) | ||
* `action`: Creates an action, see [`action`](action.md) | ||
|
||
Modifiers can be used as decorator: | ||
|
||
```javascript | ||
class TaskStore { | ||
@observable.shallow tasks = [] | ||
} | ||
``` | ||
|
||
Or as property modifier in combination with `observable.object` / `observable.extendObservable`. | ||
Note that modifiers always 'stick' to the property. So they will remain in effect even if a new value is assigned. | ||
|
||
```javascript | ||
const taskStore = observable({ | ||
tasks: observable.shallow([]) | ||
}) | ||
``` | ||
|
||
[«details»](modifiers.md) | ||
|
||
|
||
## Computed values | ||
|
||
Usage: | ||
* `computed(() => expression)` | ||
* `computed(() => expression, (newValue) => void)` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, does the setter behave as an action? |
||
* `computed(() => expression, options)` | ||
* `@computed get classProperty() { return expression; }` | ||
* `@computed.struct get classProperty() { return expression; }` | ||
|
||
Creates a computed property. The `expression` should not have side effects but return a value. | ||
The expression will automatically be re-evaluated if any observables it uses changes, but only if it is in use by some *reaction*. | ||
|
||
[«details»](computed-decorator.md) | ||
|
||
## Actions | ||
|
@@ -64,7 +147,8 @@ Usage: | |
|
||
For one-time-actions `runInAction(name?, fn, scope?)` can be used, which is sugar for `action(name, fn, scope)()`. | ||
|
||
## Reactions | ||
## Reactions & Derivations | ||
|
||
*Computed values* are **values** that react automatically to state changes. | ||
*Reactions* are **side effects** that react automatically to state changes. | ||
Reactions _can_ be used to ensure that a certain side effect (mainly I/O) is automatically executed when relevant state changes, like logging, network requests etc. | ||
|
@@ -105,16 +189,11 @@ It takes two function, the first one is tracked and returns data that is used as | |
Unlike `autorun` the side effect won't be run initially, and any observables that are accessed while executing the side effect will not be tracked. | ||
The side effect can be debounced, just like `autorunAsync`. [«details»](reaction.md) | ||
|
||
## Modifiers for `observable` | ||
|
||
By default `observable` is applied recursively and to values that are assigned in the future as well. | ||
Modifiers can be used to influence how `observable` treats specific values. | ||
* `asMap`: This is the most important modifier. Instead of creating an object with observable properties, an *Observable Map* is created instead. The main difference with observable objects is that the addition and removal of properties can be easily observed. Use `asMap` if you want a map like data structure where the keys will change over time. | ||
* `asFlat`: Will not apply `observable` recursively. The passed object / collection itself will be observable, but the values in it won't. This disables the possibility to deeply observe objects. | ||
* `asReference`: Use the passed in value verbatim, just create an observable reference to the object. | ||
* `asStructure`: When new values are assigned, ignore the new value if it structurally equal to the previous value. | ||
|
||
[«details»](modifiers.md) | ||
### `expr` | ||
Usage: `expr(() => someExpression)`. Just a shorthand for `computed(() => someExpression).get()`. | ||
`expr` is useful in some rare cases to optimize another computed function or reaction. | ||
In general it is simpler and better to just split the function in multiple smaller computed's to achieve the same effect. | ||
[«details»](expr.md) | ||
|
||
------ | ||
|
||
|
@@ -281,21 +360,6 @@ Resets MobX internal global state. MobX by defaults fails fast if an exception o | |
This function resets MobX to the zero state. Existing `spy` listeners and the current value of strictMode will be preserved though. | ||
|
||
|
||
# Functions that might get deprecated | ||
|
||
### `map` | ||
*Will probably by deprecated, use `observable(asMap())` instead*. Usage: `map()`, `map(keyValueObject)`, `map(entries)`. | ||
Returns an observable, largely ES6 compliant [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) data structure. | ||
This is useful if you want to store data based on string keys. | ||
For the full api of the returned `ObservableMap` see *Observable maps*. | ||
[«details»](map.md) | ||
|
||
### `expr` | ||
Usage: `expr(() => someExpression)`. Just a shorthand for `computed(() => someExpression).get()`. | ||
`expr` is useful in some rare cases to optimize another computed function or reaction. | ||
In general it is simpler and better to just split the function in multiple smaller computed's to achieve the same effect. | ||
[«details»](expr.md) | ||
|
||
|
||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please shortly explain the difference as in: