First, a word of caution. In this article, I am not saying that MobX is better, or that I prefer it, or anything. I use both Redux and MobX. I like both of them and probably will use both of them again. This article gives an of an application that is easy to write with MobX but very hard with Redux, if we need it to run at the same Had I not been clear, only artificial example performance level. this is an unfair comparison. Therefore this article is not a comprehensive comparison at all and should not be considered based on a real-world situation. So please don’t point to an artificial benchmark like this one and say “let’s all use instead of . It’s ” this that faster. I don’t believe there’s a single best tool. I believe that each tool has its own area where it shines and areas where it’s not so good at. There’s a time for everything. I do this kind of experiments to better understand the tools that I use, so that I can choose the right tool for the right job in the future. With that said, let’s continue. Versions Just like other things in the JavaScript world, I believe this article will get-of-date pretty quickly as things gets more optimized. That’s why I’m going to list the version numbers here: , react@15.4.1 react-dom@15.4.1 , redux@3.6.0 react-redux@5.0.0-rc.1 , mobx@2.6.4 mobx-react@4.0.3 The task: Pixel paint I’m going to create a app using React. It features a canvas that displays drawable pixels on a 128×128 grid. “pixel paint” You can paint on any pixel by hovering it with your mouse. We will render two canvases side-by-side, but both canvases share the same image. Otherwise, each pixel could’ve used its own local component state and we would not need to use any state-management library at all. Each pixel is represented by a . <div> So that’s 128×128×2=32768 DOM nodes to render and update. This experiment is going to be very slow. All tests are done on production builds. Note: The MobX version Here’s the store. (I’m avoiding the decorator syntax, because as of writing, the syntax .) is pending proposal store = observable({pixels: asMap({ }),isActive (i, j) { !!store.pixels.get(i + ',' + j)},toggle: action( toggle (i, j) {store.pixels.set(i + ',' + j, !store.isActive(i, j))})}) const return function Our canvas renders each pixel. MobXCanvas () { items = [ ] ( i = 0; i < 128; i++) { ( j = 0; j < 128; j++) {items.push(<PixelContainer i={i} j={j} key={i + ',' + j} />)}} <div>{items}</div>} function const for let for let return Each Pixel observes its own piece of state in the store. PixelContainer = observer( PixelContainer ({ i, j }) { <Pixeli={i}j={j}active={store.isActive(i, j)}onToggle={() => store.toggle(i, j)}/>}) const function return You can access the at the top-right corner of the screen. Here’s the result. [mobx-react-devtools](https://github.com/mobxjs/mobx-react-devtools) This is the result of profiling the app’s performance: In the pie chart above, scripting takes only a small fraction. Most time is spent rendering and painting. So that means MobX is doing its best job! The Redux version: first attempt Here’s the reducer: store = createStore((state = Immutable.Map(), action) => { (action.type === 'TOGGLE') { key = action.i + ',' + action.j state.set(key, !state.get(key))} state}) const if const return return The selector: selectActive = (state, i, j) => state.get(i + ',' + j) const The action creator: toggle = (i, j) => ({ type: 'TOGGLE', i, j }) const Our Redux store is ready. Our canvas provides the to each pixel: store ReduxCanvas () { items = [ ] ( i = 0; i < 128; i++) { ( j = 0; j < 128; j++) {items.push(<PixelContainer i={i} j={j} key={i + ',' + j} />)}} <Provider store={store}><div>{items}</div></Provider>} function const for let for let return And each pixel s to that . connect store PixelContainer = connect((state, ownProps) => ({active: selectActive(state, ownProps.i, ownProps.j)}),(dispatch, ownProps) => ({onToggle: () => dispatch(toggle(ownProps.i, ownProps.j))}))(Pixel) const You can use to inspect the store state, actions, and do some time traveling. Here’s the result . redux-devtools-extension It seems that this version is much slower than MobX’s version. Let’s look at the profiler. Almost 50%. That’s not good. Why is it taking so long? A significant amount of time is spent running JavaScript. Let’s do some profiling: It turns out to be how Redux’s subscription model works. In the above example, each pixel is ed to the store, which means it subscribes to the store. When it changes, each subscriber decides if it’s interested in that change, and reacts accordingly. connect That means when I change a single pixel, Redux notifies all 32,768 subscribers. This is same as Angular 1’s . And its advice also holds for Redux: dirty checking mechanism Don’t render too many things on the screen. You can’t subscribe to a subtree of your state, because that subtree is just a plain old JavaScript object which can’t be subscribed to. With Redux, you can only subscribe to the store as a whole. With MobX, every piece of state is an observable on its own. Therefore, in the MobX version, each pixel subscribes to its own state subtree. That’s why it’s so fast from the first attempt. 2nd attempt: Single subscriber So, too many subscribers can be a problem. So this time, I’ll make it so that there’s only one subscriber. Here, we create a component which will subscribe to the store and render all the pixels. Canvas ReduxCanvas () {return <Provider store={store}><Canvas /></Provider>} function Canvas = connect((state) => ({ state }),(dispatch) => ({ onToggle: (i, j) => dispatch(toggle(i, j)) }))( Canvas ({ state, onToggle }) { items = [ ] ( i = 0; i < 128; i++) { ( j = 0; j < 128; j++) {items.push(<PixelContaineri={i}j={j}active={selectActive(state, i, j)}onToggle={onToggle}key={i + ',' + j}/>)}} <div>{items}</div>}) const function const for let for let return The would then pass the props received from the to its . PixelContainer Canvas Pixel PixelContainer React.PureComponent { (props) { (props) .handleToggle = .handleToggle.bind( )}handleToggle () { .props.onToggle( .props.i, .props.j)}render () { <Pixeli={ .props.i}j={ .props.j}active={ .props.active}onToggle={ .handleToggle}/>}} class extends constructor super this this this this this this return this this this this Here’s the result . This version performs even worse that the first attempt. Let’s see what’s going on. The problem seems to be our . Since it’s the only one subscribing to the store, it’s now responsible for managing all the 16,384 pixels. Canvas with the correct props. For each store dispatch, it needs to render 16,384 **Pixel** s This means 16,384 calls followed by React trying to reconcile 16,384 children, for each canvas. Not so good. React.createElement We can do better! 3rd attempt: A balanced tree One of Redux’s key strengths is in its (which enables cool features such as painless hot-reloading and time-traveling). immutable state tree It turns out that the way we structure our data and our view is not so immutable-friendly. I discussed about this idea in this article: An immutable state tree works best when it’s stored in a balanced tree. _Why use Immutable.js instead of normal JavaScript object?_medium.com Immutable.js, persistent data structures and structural sharing So let’s do the same with our app. We’ll subdivide our canvas into four quadrants. When we need to change a pixel, We can update just the relevant quadrant, leaving other 3 quadrants alone. Instead of re-rendering all 16,384 pixels, we can re-render just 64×64=4096 pixels. This is 75% savings in performance. 4,096 is still a large number. So what we’ll do is we’ll subdivide our canvas recursively until we reach a 1×1 pixel canvas. so that when the state changes, we can use the operator to determine if the quadrant’s state has been changed or not. To be able to update the component this way, we need to structure our state in the same way too, === Here’s the code to (recursively) generate an initial state: generateInitialState = (size) => (size === 1? : Immutable.List([generateInitialState(size / 2),generateInitialState(size / 2),generateInitialState(size / 2),generateInitialState(size / 2)])) const false Now that our state is a recursively-nested tree, instead of referring to each pixel by its coordinate like (58, 52), we’re need to refer to each pixel by its path like (1, 3, 3, 2, 0, 2, 1) instead. But to present them on the screen, we need to be able to figure out the coordinates from the path: keyPathToCoordinate (keyPath) { i = 0 j = 0 ( quadrant keyPath) {i <<= 1j <<= 1 (quadrant) { 0: j |= 1; 2: i |= 1; 3: i |= 1; j |= 1; :}} [ i, j ]} function let let for const of switch case break case break case break default return And we also need to do the inverse: coordinateToKeyPath (i, j) { keyPath = [ ] ( threshold = 64; threshold > 0; threshold >>= 1) {keyPath.push(i < threshold? j < threshold ? 1 : 0: j < threshold ? 2 : 3)i %= thresholdj %= threshold} keyPath} function const for let return Now we can change our reducer to look like this: store = createStore( reducer (state = generateInitialState(128), action) { (action.type === 'TOGGLE') { keyPath = coordinateToKeyPath(action.i, action.j) state.updateIn(keyPath, (active) => !active) | }return state}) const function if const return // // This is why I use Immutable.js:// So that I can use this method. Then we create a component to traverse this tree and put everything in place. The connects to the store and renders the outermost . GridContainer Grid ReduxCanvas () { <Provider store={store}><GridContainer /></Provider>} function return GridContainer = connect((state, ownProps) => ({ state }),(dispatch) => ({ onToggle: (i, j) => dispatch(toggle(i, j)) }))( GridContainer ({ state, onToggle }) { <Grid keyPath={[ ]} state={state} onToggle={onToggle} />}) const function return Then each renders a smaller version of itself recursively until it reaches a leaf (a white/black 1x1 pixel canvas). Grid Grid React.PureComponent { (props) { (props) .handleToggle = .handleToggle.bind( )}shouldComponentUpdate (nextProps) { this.props.state !== nextProps.state}handleToggle () { [ i, j ] = keyPathToCoordinate( .props.keyPath) .props.onToggle(i, j)}render () { { keyPath, state } = .props ( state === 'boolean') { [ i, j ] = keyPathToCoordinate(keyPath) <Pixeli={i}j={j}active={state}onToggle={ .handleToggle}/>} { <div><Grid onToggle={ . .onToggle} keyPath={[ ...keyPath, 0 ]} state={state.get(0)} /><Grid onToggle={ . .onToggle} keyPath={[ ...keyPath, 1 ]} state={state.get(1)} /><Grid onToggle={ . .onToggle} keyPath={[ ...keyPath, 2 ]} state={state.get(2)} /><Grid onToggle={ . .onToggle} keyPath={[ ...keyPath, 3 ]} state={state.get(3)} /></div>}}} class extends constructor super this this this // Required since we construct a new `keyPath` every render// but we know that each grid instance will be rendered with// a constant `keyPath`. Otherwise we need to memoize the// `keyPath` for each children we render to remove this// "escape hatch." return const this this const this if typeof const return this else return this props this props this props this props Here’s the result . Phew, we are back to speed! It feels as fast as the MobX version. Plus you can do hot-reloading and time-travel as well. Our DOM tree also looks more tree-ish: Compared to all previous approaches: The ultimate optimization I haven’t coded this one because it’s useless. Here’s how: I haven’t tested this but I’m quite sure this method is the fastest way that can be accomplished with Redux. Create a Redux store for each pixel. You also lose most benefits of using Redux if you really go down this path. For example, Redux DevTools probably breaks. And time traveling one pixel at a time isn’t so useful, isn’t it? A better solution? So that’s all I can think of. If you know of a better/more elegant solution, please let me know. Updates: , which is faster than V1 but ‘less efficient than V3 but also way simpler.’ Dan Abramov submitted his version Conclusions This was a fun experiment. Many of us have a solid knowledge in optimizing imperative algorithms, but when it comes to apps based on immutable data, it can be challenging to optimize if we don’t know the performance implications. Once we optimized the Redux version, we can see that performance optimizations can result in a less readable code. What a mess I did above! As said, (and so is MobX). So, will you trade the clarity and readability of your code for performance without losing the ability to hot-reload and do time-travel? Dan Abramov Redux offers a trade-off In my project, the app will be run in MobileSafari, so performance matters a lot, especially when an instrument may contain hundreds of buttons. midi-instruments I also want to quickly prototype new instruments without having to worry about performance implications when I use immutable data. I also find hot-reloading and time-traveling not-so-useful in this project. Most of the state lasts for a few seconds and my project is small enough that I can just reload the page. So I happily use MobX in this project. In a rhythm game that I’m building, , I feel that using immutable data helps me write simple and easy-to-test code. Bemuse I don’t have to worry about unexpected state mutations because there is nothing to be mutated. There’s not too much data to render either, so I probably don’t need to optimize it like the above example. Having a Redux DevTools at hand and would also benefit me a lot. Here, Redux shines a lot! all state-updating centralized at a single place So I happily use Redux in this project. An unfair performance comparison This comparison has been unfair from the beginning when I try to compare a functional approach (Redux) with an imperative approach (MobX). In 1996, Chris Okasaki concluded in his , that: 140-page thesis ‘Purely Functional Data Structures’ Regardless of the advances in compiler technology, functional programs will never be faster than their imperative counterparts as long as the algorithms available to functional programmers are significantly slower than those available to imperative programmers. In that thesis ( ), he tried to make data structures in functional programming as efficient its imperative counterpart. now available as a book This thesis provides numerous functional data structures that are asymptotically just as efficient as the best imperative implementations I would not stop doing functional programming just because it can never be as fast as imperative algorithm… It’s all about trade-offs. That’s why I never say ‘let’s use Redux/MobX for .’ That’s why I can’t provide an adequate answer when people asked “should I use MobX or Redux in 2017?” without any other context. That’s why I wrote this article. everything! Thanks for reading! There’s some good discussion on Reddit! There’s some more discussion in Dan Abramov’s pull request (thanks!): _It's less efficient than V3 but also way simpler. Relies on memoization of props (which is something you want to do in…_github.com Add a simple but reasonably fast Redux version by gaearon · Pull Request #1 · dtinth/pixelpaint