Enjoying MobX, JSX and virtual-dom

Without React!

Alfonso de la Osa
4 min readJun 7, 2016

The future of the front-end web development landscape is likely to be based in a micro-libraries environment where the developer can choose the set of utilities that she needs. React has shown that this is now a reality: it provides the view and it is not opinionated about how you engineer the rest. Taking Flux as an example, we can see how the community has iterated over the paradigm until Dan Abramov’s Redux appeared. Now Michel Weststrate’s MobX is offering state management based on the observable pattern.

If React provided an implementation for state management in the first place, it probably would have suffered the same fate as Backbone or Angular by now. The same can be said about routing, etc.

In that line of thought, Jake Verbaten’s gist expressed the idea of a virtual DOM and diffing library independent of React. This is how virtual-dom started.

TL;TR

This article shows how easy it is to use virtual-dom’s diffing algorithm with a MobX observable to trigger the DOM updates. JSX is used for the view.

I have put all the code together in this repo and you can run the dev server like this:

git clone https://github.com/botverse/vdom-mobx-example
cd vdom-mobx-example
npm install
npm run dev

Motivation

Recently I have been using my spare time to play with some experiments, and I was finding myself getting tired by the time it took to start coding. So I looked for a quicker start. This article describes my findings.

The pieces

MobX is a trendy library for state management. It simplifies the minimum boilerplate needed for a small project, as it states in the docs:

Everything that can be derived from the application state, should be derived. Automatically.

A simple usage of MobX would be:

In this example, MobX captures the usage of any observable inside the autorun’s argument function, and then executes it again every time the observable that we have provided changes.

Here is a quick example of the usage of virtual-dom, as per the documentation:

What we see here is a second by second re-render of the virtual-dom tree, based on the patch obtained after diffing the previous tree.

If you want to know more about the diffing algorithm, read this article.

And finally, here is an example of JSX, an XML-like syntax extension to JavaScript that can be compiled into plain JavaScript. In our case we will compile it to calls to virtual-dom/hyperscript’s h() function:

Putting it all together

Thanks to MobX observer, and in not many lines of code, we can have a view that reacts to user input.

Four important, not-so-magical things are happening there, namely the MobX observable, an arrow function as an event listener (onclick), a chunk of JSX written directly into JavaScript (the view), and a call to function mount which mounts the view into the dom.

The mount function is tiny:

mount uses MobX autorun to listen to the changes, then calls render when any used observable changes occur, rendering the whole tree. It is still quite performant because of virtual-dom’s diff and patch.

Now we only need a index.html file to be served:

Setting up babel and webpack

First of all we need to init our npm module and install some modules.

If we want to use JSX without React we need babel-plugin-transform-h-jsx and esutils (required by transform-h-jsx). Otherwise the dependencies are babel (and plugins), webpack (and its server), virtual-dom and MobX.

Webpack is not mandatory; you can achieve the same result with babelify, or by running babel directly from babel-cli, using this configuration:

Feel free to use your favourite bundler. If you feel lazy you can just copy this webpack.config.js

Heads up! For simplicity of this example, I am auto-importing the virtual-dom h() function using webpack’s ProvidePlugin. Without that configuration, you should import h to every file in which you would use it: import h from ‘virtual-dom/h’; in the same fashion you would import React into a module where you use JSX.

The important configuration is added as babel plugins: transform-h-jsx to convert JSX into virtual-dom’s hyperscript:

<div/> => h(‘div’)

And you need to add transform-decorators-legacy to be able to use decorators:

{ @observable count: 0 }

They have been removed from babel 6 until the proposal advances.

Place the app.js file in the ./src directory and the index.html file in the ./build directory. This is for webpack to be able to find them. As per the configuration above, webpack will read the sources, apply babel transformations to files inside ./src, and serve them along with the contents of ./build (where our index.html is).

If you want to make the dev server easy to run, you can add a npm command like this:

So you can run:

npm run dev

Disclaimer

The technique, as described here is not as performant as if you were using React with Immutable and shouldComponentUpdate. In React you can opt-out from render if its data is the same. I will describe how to handle this situation in a future post.

Another issue is that with MobX alone it is difficult to track changes, for example it would be difficult to implement undo/redo.

--

--