1 | <img src="https://mobx.js.org/assets/mobx.png" alt="logo" height="120" align="right" />
|
2 |
|
3 | # MobX
|
4 |
|
5 | _Simple, scalable state management._
|
6 |
|
7 | [![npm version](https://badge.fury.io/js/mobx.svg)](https://badge.fury.io/js/mobx)
|
8 | [![OpenCollective](https://opencollective.com/mobx/backers/badge.svg)](docs/backers-sponsors.md#backers)
|
9 | [![OpenCollective](https://opencollective.com/mobx/sponsors/badge.svg)](docs/backers-sponsors.md#sponsors)
|
10 | [![Discuss on Github](https://img.shields.io/badge/discuss%20on-GitHub-orange)](https://github.com/mobxjs/mobx/discussions)
|
11 | [![Coverage Status](https://coveralls.io/repos/github/mobxjs/mobx/badge.svg?branch=main)](https://coveralls.io/github/mobxjs/mobx?branch=main)
|
12 | [![View changelog](https://img.shields.io/badge/changelogs.xyz-Explore%20Changelog-brightgreen)](https://changelogs.xyz/mobx)
|
13 |
|
14 | ---
|
15 |
|
16 | ## Documentation
|
17 |
|
18 | Documentation can be found at **[mobx.js.org](https://mobx.js.org/)**.
|
19 |
|
20 | ---
|
21 |
|
22 | ## Sponsors
|
23 |
|
24 | MobX is made possible by the generosity of the sponsors below, and many other [individual backers](https://github.com/mobxjs/mobx/blob/main/docs/backers-sponsors.md#backers). Sponsoring directly impacts the longevity of this project.
|
25 |
|
26 | **🥇 Gold sponsors (\$3000+ total contribution):** <br/>
|
27 | <a href="https://mendix.com/"><img src="https://mobx.js.org/assets/mendix-logo.png" align="center" width="100" title="Mendix" alt="Mendix" /></a>
|
28 | <a href="https://www.guilded.gg/"><img src="https://mobx.js.org/assets/guilded.jpg" align="center" width="100" title="Guilded" alt="Guilded" /></a>
|
29 | <a href="https://www.getparallax.com/"><img src="https://mobx.js.org/assets/parallax.png" align="center" width="100" title="Parallax" alt="Parallax" /></a>
|
30 | <a href="https://frontendmasters.com/"><img src="https://mobx.js.org/assets/frontendmasters.jpg" align="center" width="100" title="Frontend Masters" alt="Frontend Masters"></a>
|
31 | <a href="https://www.one-beyond.com"><img src="https://mobx.js.org/assets/dcsl.png" align="center" width="100" title="One Beyond" alt="One Beyond"/></a>
|
32 | <a href="http://auctionfrontier.com/"><img src="https://mobx.js.org/assets/auctionfrontier.jpeg" align="center" width="100" title="Auction Frontier" alt="Auction Frontier"></a>
|
33 | <a href="https://www.codefirst.co.uk/"><img src="https://mobx.js.org/assets/codefirst.png" align="center" width="100" title="CodeFirst" alt="CodeFirst"/></a>
|
34 | <a href="https://modulz.app/"><img src="https://mobx.js.org/assets/modulz.png" align="center" width="100" title="Modulz" alt="Modulz"/></a>
|
35 | <a href="https://coinbase.com/"><img src="https://mobx.js.org/assets/coinbase.jpeg" align="center" width="100" title="Coinbase" alt="Coinbase" /></a>
|
36 | <a href="https://curology.com/blog/tech"><img src="https://mobx.js.org/assets/curology.png" align="center" width="100" title="Curology" alt="Curology"/></a>
|
37 | <a href="https://opensource.facebook.com/"><img src="https://mobx.js.org/assets/fbos.jpeg" align="center" width="100" title="Facebook Open Source" alt="Facebook Open Source" /></a>
|
38 | <a href="https://www.canva.com/"><img src="https://mobx.js.org/assets/canva.png" align="center" width="100" title="Canva" alt="Canva" /></a>
|
39 |
|
40 | **🥈 Silver sponsors (\$100+ per month):**<br/>
|
41 |
|
42 | <a href="https://casinosites.ltd.uk/?utm_source=sponsorship&utm_medium=mobx&utm_campaign=readme"><img src="https://mobx.js.org/assets/casino2.png" align="center" width="100" title="Casino Sites" alt="Casino Sites"/></a>
|
43 | <a href="https://upper.co/?utm_source=github_mobxjs_sponsorship&utm_medium=paid_acquisition&utm_campaign=sponsorship"><img src="https://mobx.js.org/assets/upper.png" align="center" width="100" title="UPPER" alt="UPPER"/></a>
|
44 | <a href="https://www.easeus.com/?utm_source=github_mobxjs_sponsorship&utm_medium=readme&utm_campaign=sponsorship"><img src="https://mobx.js.org/assets/easeus.png" align="center" width="100" title="EaseUS" alt="EaseUS"/></a>
|
45 |
|
46 | **🥉 Bronze sponsors (\$500+ total contributions):**<br/>
|
47 | <a href="https://www.bugsnag.com/platforms/react-error-reporting?utm_source=MobX&utm_medium=Website&utm_content=open-source&utm_campaign=2019-community&utm_term=20190913"><img src="https://mobx.js.org/assets/bugsnag.jpg" align="center" width="100" title="Bugsnag" alt="Bugsnag"/></a>
|
48 | <a href="https://space307.com/?utm_source=sponsorship&utm_medium=mobx&utm_campaign=readme"><img src="https://mobx.js.org/assets/space307.png" align="center" width="100" title="Space307" alt="Space307"/></a>
|
49 | <a href="https://mantro.net/jobs/warlock"><img src="https://mobx.js.org/assets/mantro.png" align="center" width="100" title="mantro GmbH" alt="mantro GmbH"></a>
|
50 | <a href="https://www.algolia.com/"><img src="https://mobx.js.org/assets/algolia.jpg" align="center" width="100" title="Algolia" alt="Algolia" /></a>
|
51 | <a href="https://talentplot.com/"><img src="https://mobx.js.org/assets/talentplot.png" align="center" width="100" title="talentplot" alt="talentplot"></a>
|
52 | <a href="https://careers.dazn.com/"><img src="https://mobx.js.org/assets/dazn.png" align="center" width="100" title="DAZN" alt="DAZN"></a>
|
53 | <a href="https://blokt.com/"><img src="https://mobx.js.org/assets/blokt.jpg" align="center" width="100" title="Blokt" alt="Blokt"/></a>
|
54 |
|
55 | ---
|
56 |
|
57 | ## Introduction
|
58 |
|
59 | _Anything that can be derived from the application state, should be. Automatically._
|
60 |
|
61 | MobX is a battle-tested library that makes state management simple and scalable by transparently applying functional reactive programming.
|
62 | The philosophy behind MobX is simple:
|
63 |
|
64 | <div class="benefits">
|
65 | <div>
|
66 | <div class="pic">😙</div>
|
67 | <div>
|
68 | <h4>Straightforward</h4>
|
69 | <p>Write minimalistic, boilerplate-free code that captures your intent.
|
70 | Trying to update a record field? Simply use a normal JavaScript assignment —
|
71 | the reactivity system will detect all your changes and propagate them out to where they are being used.
|
72 | No special tools are required when updating data in an asynchronous process.
|
73 | </p>
|
74 | </div>
|
75 | </div>
|
76 | <div>
|
77 | <div class="pic">🚅</div>
|
78 | <div>
|
79 | <h4>Effortless optimal rendering</h4>
|
80 | <p>
|
81 | All changes to and uses of your data are tracked at runtime, building a dependency tree that captures all relations between state and output.
|
82 | This guarantees that computations that depend on your state, like React components, run only when strictly needed.
|
83 | There is no need to manually optimize components with error-prone and sub-optimal techniques like memoization and selectors.
|
84 | </p>
|
85 | </div>
|
86 | </div>
|
87 | <div>
|
88 | <div class="pic">🤹🏻♂️</div>
|
89 | <div>
|
90 | <h4>Architectural freedom</h4>
|
91 | <p>
|
92 | MobX is unopinionated and allows you to manage your application state outside of any UI framework.
|
93 | This makes your code decoupled, portable, and above all, easily testable.
|
94 | </p>
|
95 | </div>
|
96 | </div>
|
97 | </div>
|
98 |
|
99 | ---
|
100 |
|
101 | ## A quick example
|
102 |
|
103 | So what does code that uses MobX look like?
|
104 |
|
105 | ```javascript
|
106 | import React from "react"
|
107 | import ReactDOM from "react-dom"
|
108 | import { makeAutoObservable } from "mobx"
|
109 | import { observer } from "mobx-react"
|
110 |
|
111 | // Model the application state.
|
112 | class Timer {
|
113 | secondsPassed = 0
|
114 |
|
115 | constructor() {
|
116 | makeAutoObservable(this)
|
117 | }
|
118 |
|
119 | increase() {
|
120 | this.secondsPassed += 1
|
121 | }
|
122 |
|
123 | reset() {
|
124 | this.secondsPassed = 0
|
125 | }
|
126 | }
|
127 |
|
128 | const myTimer = new Timer()
|
129 |
|
130 | // Build a "user interface" that uses the observable state.
|
131 | const TimerView = observer(({ timer }) => (
|
132 | <button onClick={() => timer.reset()}>Seconds passed: {timer.secondsPassed}</button>
|
133 | ))
|
134 |
|
135 | ReactDOM.render(<TimerView timer={myTimer} />, document.body)
|
136 |
|
137 | // Update the 'Seconds passed: X' text every second.
|
138 | setInterval(() => {
|
139 | myTimer.increase()
|
140 | }, 1000)
|
141 | ```
|
142 |
|
143 | The `observer` wrapper around the `TimerView` React component will automatically detect that rendering
|
144 | depends on the `timer.secondsPassed` observable, even though this relationship is not explicitly defined. The reactivity system will take care of re-rendering the component when _precisely that_ field is updated in the future.
|
145 |
|
146 | Every event (`onClick` / `setInterval`) invokes an _action_ (`myTimer.increase` / `myTimer.reset`) that updates _observable state_ (`myTimer.secondsPassed`).
|
147 | Changes in the observable state are propagated precisely to all _computations_ and _side effects_ (`TimerView`) that depend on the changes being made.
|
148 |
|
149 | <img alt="MobX unidirectional flow" src="https://mobx.js.org/assets/flow2.png" align="center" />
|
150 |
|
151 | This conceptual picture can be applied to the above example, or any other application using MobX.
|
152 |
|
153 | ## Getting started
|
154 |
|
155 | To learn about the core concepts of MobX using a larger example, check out **[The gist of MobX](https://mobx.js.org/the-gist-of-mobx.html)** page, or take the **[10 minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)**.
|
156 | The philosophy and benefits of the mental model provided by MobX are also described in great detail in the blog posts [UI as an afterthought](https://michel.codes/blogs/ui-as-an-afterthought) and [How to decouple state and UI (a.k.a. you don’t need componentWillMount)](https://hackernoon.com/how-to-decouple-state-and-ui-a-k-a-you-dont-need-componentwillmount-cc90b787aa37).
|
157 |
|
158 | ## Further resources
|
159 |
|
160 | - The [MobX cheat sheet](https://gum.co/fSocU) (£5) is both useful and sponsors the project
|
161 | - [10 minute interactive introduction to MobX and React](https://mobx.js.org/getting-started)
|
162 | - [Egghead.io course, based on MobX 3](https://egghead.io/courses/manage-complex-state-in-react-apps-with-mobx)
|
163 | - The [MobX awesome list](https://github.com/mobxjs/awesome-mobx#awesome-mobx) – a long list of MobX resources and example projects
|
164 |
|
165 | ### The MobX book
|
166 |
|
167 | <a href="https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837"><img src="https://mobx.js.org/assets/book.jpg" height="120px" /></a>
|
168 |
|
169 | The **[MobX Quick Start Guide](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837)** ($24.99) by [Pavan Podila](https://twitter.com/pavanpodila) and [Michel Weststrate](https://twitter.com/mweststrate) is available as an [ebook](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837), [paperback](https://www.amazon.com/MobX-Quick-Start-Guide-Supercharge/dp/1789344832), and on the [O'Reilly platform](https://www.oreilly.com/library/view/mobx-quick-start/9781789344837/) (see [preview](https://books.google.com/books?id=ALFmDwAAQBAJ&printsec=frontcover#v=onepage&q&f=false)).
|
170 |
|
171 | ### Videos
|
172 |
|
173 | - [Introduction to MobX & React in 2020](https://www.youtube.com/watch?v=pnhIJA64ByY) by Leigh Halliday, _17 min_.
|
174 | - [ReactNext 2016: Real World MobX](https://www.youtube.com/watch?v=Aws40KOx90U) by Michel Weststrate, _40 min_, [slides](https://docs.google.com/presentation/d/1DrI6Hc2xIPTLBkfNH8YczOcPXQTOaCIcDESdyVfG_bE/edit?usp=sharing).
|
175 | - [CityJS 2020: MobX, from mutable to immutable, to observable data](https://youtu.be/sP7dtZm_Wx0?t=27050) by Michel Weststrate, _30 min_.
|
176 | - [OpenSourceNorth: Practical React with MobX (ES5)](https://www.youtube.com/watch?v=XGwuM_u7UeQ) by Matt Ruby, _42 min_.
|
177 | - [HolyJS 2019: MobX and the unique symbiosis of predictability and speed](https://www.youtube.com/watch?v=NBYbBbjZeX4&list=PL8sJahqnzh8JJD7xahG5zXkjfM5GOgcPA&index=21&t=0s) by Michel Weststrate, _59 min_.
|
178 | - [React Amsterdam 2016: State Management Is Easy](https://www.youtube.com/watch?v=ApmSsu3qnf0&feature=youtu.be) by Michel Weststrate, _20 min_, [slides](https://speakerdeck.com/mweststrate/state-management-is-easy-introduction-to-mobx).
|
179 | - {🚀} [React Live 2019: Reinventing MobX](https://www.youtube.com/watch?v=P_WqKZxpX8g) by Max Gallo, _27 min_.
|
180 |
|
181 | ## Credits
|
182 |
|
183 | MobX is inspired by reactive programming principles, which are for example used in spreadsheets. It is inspired by model–view–viewmodel frameworks like [MeteorJS's Tracker](https://docs.meteor.com/api/tracker.html), [Knockout](https://knockoutjs.com/) and [Vue.js](https://vuejs.org/), but MobX brings _transparent functional reactive programming_ (TFRP, a concept which is further explained in the [MobX book](https://www.packtpub.com/product/mobx-quick-start-guide/9781789344837)) to the next level and provides a standalone implementation. It implements TFRP in a glitch-free, synchronous, predictable and efficient manner.
|
184 |
|
185 | A ton of credit goes to [Mendix](https://github.com/mendix), for providing the flexibility and support to maintain MobX and the chance to prove the philosophy of MobX in a real, complex, performance critical applications.
|