About the Author:

The Journey from Vue to MobX

August 25th, 2017

I recently began using React with MobX at my new company. Having used Vue with VueX at my previous job, I immediately noticed congruence between the two patterns. What I had become so fond of with Vue after being a long time React/Redux user, I found baked into the MobX philosophy.

I’ve seen a lot of people adopting Vue this year. Sarah Drasner’s fantastic series on CSSTricks probably played a big part in that migration. However I believe we JS developers live in a meritocracy (for the most part) and I mainly credit this diaspora to a few things:

  • event handling
  • multiple rendering options (templates or render functions with JSX)
  • truly reactive components

This last point is the kicker. Vue has reactivity baked directly into its components. I think this simplicity and thoughtful architecture is the main reason for all the hype and it’s why I took such a liking to Vue. This is not a novel concept, as we’ve seen native reactivity in frameworks like Ember and Knockout before, but its elegance in Vue makes it superior.

This piece is not meant to be a comparison of React + MobX and Vue + VueX. This post from the Vue docs that topped HackerNews last week does a fair job at this. I earnestly believe both solutions are great and have their use cases. This this post aims to do is introduce MobX concepts from the perspective of someone who loves Vue reactivity.

Enter MobX

When I first learned that I was would be moving to Vue professionally, I privately grieved. There were many things I initially missed: a large developer community, dedicated support from a tech powerhouse in Facebook; however, the thought of going back to my days of Redux boilerplates and a more verbose state management solution was less than enticing.

In fact, I came to appreciate thinking in “the Vue way” so much so that I expressed that same sadness when I learned that I would be moving back to React. That is until I learned that my new team was using MobX.

The state management pattern that MobX brings to a view framework like React might seem so similar to Vue that at first you might ask yourself…

Evan You tweet on MobX

Although humorous (and somewhat true), I see this as a mostly straw man argument. MobX does not claim to supplant Vue and its ideology. What it does offer is a less-opinionated and more robust alternative to the reactive data management pattern built into Vue.

Travel Log

In this section, I want to demonstrate how we might write some code in Vue, followed by its implementation with React + MobX. As a basis for our comparison, let’s use a tiny app I built that lists several places around the world and let’s us mark the locations of the ones we’ve visited.

An app like this requires the use of state to manage our currently selected location and the list of places we’ve visited. I’ve implemented the app three different ways: once using React local state, once more in Vue, and one last time with React + MobX. We’ll go through the general paradigms of local state management using the logic contained in these apps.

data => observable

State is essential to any complex application. While React provides an option for managing local state, it requires usage of the setState function and is limited to a single object. Vue introduces data, instead, as a mechanism for declaring reactive local variables.

In our app, we use data to keep track of the cities we’ve visited, our currently selected city, and a few variables we need to manage the alert.

data: function() {
return {
cities: cities,
selectedCityId: null,
visited: {},
alert: false,
clearAlert: null
}
},

Just like that, this data (i.e. your state) is now reactive. You can update these variables from any JS within the Vue component and Vue will re-render the component if necessary. This removes the need to use setState — or any other function for that matter — to update local state.

MobX takes a similar approach, but instead of a singular data object your reactive variables are wrapped in observables.

cities = cities;
@observable selectedCityId;
@observable visited = {};
@observable showAlert = false;
@observable clearAlert;

By wrapping your component in an observer from the mobx-react connector library, the component becomes reactive to mutations of these variables. Like Vue, the component will now update when they are used in the render function of the component.

computed => computed

The addition of computed variables begins to shine light on the advantage of this approach. When only using local state, we are left to compute certain variables every time the component renders. Computed variables allows us to compute a new value every time a dependent variable changes, caching that value until one of the dependencies changes.

computed: {
selectedCity() {
return this.cities.find(city => city.id === this.selectedCityId);
},
sortedCities() {
return this.cities.sort((a, b) => a.name > b.name ? 1 : -1);
}
},

In our app, Vue computes an alphabetically sorted version of the cities array. This is preferred over computing it every time we render, as this array does not actually change throughout the lifecycle of our component. As these transformations become more expensive, this feature becomes crucial for building a performant PWA.

MobX gives us the same ability with its computed object.

extendObservable(this, {
cities,
sortedCities: computed(function() {
return this.cities.sort((a, b) => a.name > b.name ? 1 : -1);
}),
selectedCity: computed(function() {
return this.cities.find(city => city.id === this.selectedCityId);
})
})

The only difference here is syntax. All the spoils remain the same.

method => action

One major difference between Vue and React is the makeup of the components themselves. Vue eschews ES6 classes in favor of custom components with specific options (i.e. data, computed, etc). This gives it tight control over where the user can control certain behavior and certainly brings a sense of organization to each component. One place where this is evident are the method functions. These are the only functions capable of updating local state that you can explicitly invoke from within your template (for the sake of this discussion, that is).

methods: {
selectCity(cityId) {
this.selectedCityId = cityId;
},

toggleCity(cityId) {
if (this.visited[cityId]) {
const { [cityId]: city, ...rest } = this.visited;
this.visited = rest;
} else {
this.visited = { ...this.visited, [cityId]: true };
}
}
}

Nothing too crazy here. We select a city and update the selectedCityId accordingly. We can, of course, write this logic inline in our click handlers, but methods help us organize our code and keep it DRY.

Lo and behold, the MobX equivalent is not too far off with actions.

@action selectCity(cityId) {
this.selectedCityId = cityId;
}

@action toggleCity(cityId) {
if (this.visited[cityId]) {
const { [cityId]: city, ...rest } = this.visited;
this.visited = rest;
} else {
this.visited = { ...this.visited, [cityId]: true };
}
}

There really isn’t much of a difference here at the base level. In fact, you don’t even need to use actions to update local observables. You can simply update your observables in regular functions, as long as strict mode is not enabled. Where actions become beneficial is in their inherent performance boost, described in the docs as such:

…actions will batch mutations and only notify computed values and reactions after the (outer most) action has finished. This makes sure intermediate or incomplete values produced during an action are not visible to the rest of the application until the action has finished.

With the addition of runInAction, this makes writing complex state-updating functions easier by simplifying the predictability of your component’s state.

watch => reaction

The final piece to any complex component’s state management suite is its need for imperative code. In our app, for example, we want to display an alert banner every time the user updates their log. When using only React’s local state, we are forced to explicitly tell the banner to appear with the showAlert function. Acting strictly as a view layer, React’s goal is not to emit side effects, so it only makes sense that local state does not provide us with optimal ways to produce them. However, any front end developer knows that these are unavoidable when building a robust UI. If only there was a way for us to react to specific state updates…

Thinking

As you may have expected, Vue gives us the handy concept of watch to do just that.

watch: {
visited() {
if (this.clearAlert) {
clearTimeout(this.clearAlert);
}

this.clearAlert = setTimeout(() => {
this.alert = false;
}, 3000);
this.alert = true;
}
},

This piece of code essentially says that every time our visited object changes, we run a function in response. I love this pattern because it no longer requires us to think about when we need to display our alert. Instead, our code just knows that every time we update our log, the banner should display. We are even given a deep option for instructing Vue to watch for mutations deep within our state objects, meaning immutability is not even required for this functionality.

Not surprisingly, MobX offers almost identical functionality with reactions.

const updatedLog = reaction(
()=> this.visited,
() => {
if (this.clearAlert) {
clearTimeout(this.clearAlert)
}

this.clearAlert = setTimeout(() => {
this.showAlert = false;
}, 3000)
this.showAlert = true
}
);

Admittedly, it’s not as clear what is going on here at first glance, so let’s break it down.

A reaction takes two functions as arguments. The first instructs what state variables to watch, while the second contains the code to run when one of those values mutates.

While Vue offers simplicity when it comes to imperative code, MobX rebuttals with power. Reactions are capable of listening to multiple observables at once and only reacting a single time to one mutation, something I always found difficult to work around with watch. MobX also offers a suite of tools that give you more fine-grained control for running imperative code. autorun will simply run when any of its dependencies change, while when replaces the first function with a predicate, only running the latter if the former returns true. This can all be achieved in some fashion with reaction, but these helper functions work to make your state…dare I say it…predictable.

The Verdict

It’s an unequivocal tie!

In all seriousness, both of these patterns are great and provide similar mechanisms for performing the same goals. This piece was simply meant to enlighten developers on the parallels between both libraries. I really do like to use them both in different situations.

However, I would be remiss if I didn’t provide a short (possibly subjective) list of where I think each approach stands out:

MobX Wins

  1. ES7 & Beyond: MobX takes full advantage of recent additions to the language, most blatantly classes and decorators. These are newer concepts to JS, but they provide tried and true patterns that have existed in other languages like Python for eons. Best of all, they are not required, so you can easily use MobX without them.
  2. Predictability: Vue does a great job at this, but I think MobX wins out here. MobX builds out an insanely complex dependency graph behind the scenes that runs all your reactive code synchronously. This is crucial for debugging and actually understanding what the hell is going on in your code!
  3. Extensibility: MobX just works in its own right, so you can use it in just about any context you’d like. Vue’s clean syntax comes at the cost of tightly-coupling your source code with a particular framework. So far I’ve only used it with React projects, but it can just as easily be used in Preact, Inferno, and other rising stars.

Vue Wins

  1. Modifiers: In addition to the basic actions, Vue provides event modifiers and other niceties for writing clean code. It’s a clear indicator to the thought that went in to making this an approachable framework for developers and it speaks to the relevancy of directives.
  2. Documentation: Vue definitely excels here. The documentation is succinct, well-organized, and in-depth in the right areas. Again, this shines a light on the delightful developer experience Vue seeks to provide.
  3. Organization: This can go either way, but as someone obsessed with linting and prettier, Vue brings a very understandable pattern to your development workflow. Everything is where it needs to be, making code handoffs and reviews a more seamless process for a collaborative team.
  4. Clean DOM: For all the benefits of decorators, inject and observer (from mobx-react) do muddy up the DOM with extraneous wrapper components. This becomes frustrating during debugging using the React dev tools and looking for your actual component among the redwood of a tree. Vue keeps the DOM nice and tidy by only rendering your custom components.

Conclusion

My hope for this post was that you got a basic understanding of the similarities between MobX and Vue for managing local state. Both libraries have done a fantastic job of identifying pain points experience by UI developers in recent years and building pragmatic tools to address them. These paradigms can solve many higher-order problems, as well: managing global state with VueX and MobX, handling streams, and proxies.

Feel free to reach out with any questions/comments via the issues of the vue-mobx repo I made containing this post’s code. Go forth and explore the possibilities!

Additional Resources

About the Author:

Using Mobx + Firebase to build a Twitter Clone

March 22nd, 2017

In this tutorial I’ll be showing you how to create a very Twitter Clone using React and Firebase. MobX will be used as the data store for Firebase data. Here’s what the final output is going to look like:

MobX-Firebase Twitter Clone

Firebase Setup

In order to not bog us down in Firebase setup, this tutorial will assume that you already have an existing Firebase project created in the Firebase Console. If not, go ahead and create one. Once you have a project, go to the database section and under the rules tab add the following:

{
  "rules": {
    ".read": true,
    ".write": true
  }
}

This sets read and write permissions of your database to public. This means you don’t need to authenticate later on in order to gain access the database. This is good for quickly getting started with something, but not for production apps. Be sure to change this later!

Project Setup

Clone the create-react-app-mobx project. This allows you to easily create a React Project which has already the MobX toolset built into it (the original create-react-app doesn’t support all MobX features yet).

git clone https://github.com/mobxjs/create-react-app-mobx.git react-firebase-mobx-twitter-clone

Next, open your package.json file and add the following:

"mobx-firebase-store": "^1.0.3",
"react-timeago": "^3.2.0",
"chance": "^1.0.6",
"slugify": "^1.1.0",
"twitter-text": "^1.14.3"

Here’s a breakdown of what each package does:

  • mobx-firebase-store – used for storing Firebase data in MobX maps. This uses Firebase-nest as a peer dependency to subscribe to changes in a Firebase store.
  • react-timeago – used for generating a human-friendly text based on a timestamp.
  • chance – used for generating a random name to be assigned to the current user.
  • slugify – used for making the random name URL-friendly.
  • twitter-text – contains utility functions for working with twitter text. Things like counting the remaining text and converting URL’s into links.

Execute npm install to install all the packages. Once that’s done, you can run npm start to serve the project for development. You can access https://localhost:3000 on your browser to view the project.

Creating the Main Component

Before moving on, delete everything inside the src folder of the project. By default it contains a demo project that uses MobX to implement a counter app. We don’t really need those so you can go ahead and delete them.

Create an index.js file. This is where you supply your Firebase database URL and render the main app component which you’ll be creating later:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const config = {
    databaseURL: 'https://{YOUR_FIREBASE_PROJECT_NAME}.firebaseio.com',
};

ReactDOM.render(
  ,
  document.getElementById('root')
);

Next, create an App.js file. This is where you import the TweetList component we’ll build that serves as the component that the user will interact with, and the TweetStore store which contains the code for connecting, and saving/reading data from Firebase.

import React, { Component } from 'react';
import TweetList from './TweetList';
import TweetStore from './TweetStore';
import './index.css';

class App extends Component {

  componentWillMount() {
    this.store = new TweetStore(this.props.config); //create a new instance of the store by passingin the Firebase config
  }

  render() {
    return (
      

MobX-Firebase Twitter Clone

); } } export default App;

Creating the TweetList Component

Now we’ll create the TweetList.js file. At the very top, import all the libraries and components that you need. You’ll see how each of these will be used later so we won’t cover what each one does here.

import React, { Component } from 'react';

import { observer } from 'mobx-react';
import { createAutoSubscriber } from 'firebase-nest';

import Chance from 'chance';
import slugify from 'slugify';
import TimeAgo from 'react-timeago'
import twitter_text from 'twitter-text';

const tweet_limit = 140;
var ch = new Chance();

Next, create the Tweetlist component. Initialize the state as well as the functions inside the constructor.

class TweetList extends Component {

  constructor(props) {
    super(props);
    this.state = {
      tweet: '', //the user's tweet text
      username: slugify(ch.name()),
      loading: false, //whether the Firebase data is currently loading or not
      remaining: tweet_limit //number of characters allowed for each tweet
    };
    this.updateText = this.updateText.bind(this); 
    this.submitTweet = this.submitTweet.bind(this); 
  }
  ...
}

The render() method uses the getTweets() method from the store. You’ll be creating this later, for now know that everytime someone makes a change to your Firebase database, the component gets re-rendered. If the Firebase data becomes available, the textarea for entering the tweet and the list of tweets gets rendered.

render() {
  const tweets = this.props.store.getTweets();
  if (!tweets) {
    return 
Loading tweets...
} return (
{this.state.username}
{this.state.remaining}
{tweets.keys().reverse().map(messageKey => this.renderTweet(messageKey, tweets.get(messageKey)))}
); }

Here’s the function for rendering each tweet:

renderTweet(key, tweet) {
  return (
    
@{tweet.username} -
); }

The function for updating the state of the current tweet text and remaining count:

updateText(evt) {
  let tweet = evt.target.value
  let remaining = tweet_limit - twitter_text.getTweetLength(tweet);
  this.setState({
    tweet,
    remaining
  });
}

The function for saving the tweet in Firebase:

submitTweet() {
  this.props.store.createTweet({
    username: this.state.username,
    timestamp: new Date().getTime(),
    text: this.state.tweet 
  });

  this.setState({
    tweet: '',
    remaining: tweet_limit
  });
}

Next, you need to define the getSubs() and subscribeSubs() function. The naming is relevant because the Firebase-nest library rely on these two functions. getSubs() returns the array of subscriptions while subscribeSubs() performs the subscription and returns the function for unsubscribing from the Firebase data.

getSubs(props, state) {
  return props.store.allTweetsSubs();
}

subscribeSubs (subs, props, state) {
  return props.store.subscribeSubs(subs);
}

Finally, you use the createAutoSubscriber() function to subscribe and observe to Firebase data. This function uses the getSubs() and subscribeSubs() functions that you defined earlier in order to subscribe to Firebase data and propagate the changes in the store. It will then return the function that requires a Reactive component to be passed in. We can turn our component into a Reactive one by wrapping it in MobX’s observer() function. This ensures that any data that is used for rendering the component forces a re-rendering when it’s updated. If you don’t set your component as an observer, it won’t re-render when the current user or someone else posts a new tweet.

export default createAutoSubscriber()(observer(TweetList));

Creating the Store

We shall now create out Mobx store. Create a TweetStore.js file. This serves as the store for the TweetList component. It contains the methods for saving and fetching data from Firebase.

Start by importing firebase and mobx-firebase-store. firebase is the official Firebase JavaScript library for working with Firebase. This allows you to connect to Firebase. The mobx-firebase-store library provides a bridge between the Firebase library and the MobX library. It allows you to subscribe to Firebase data through the use of firebase-nest subscriptions. This makes the data flow into MobX’s observable maps.

import Firebase from 'firebase';
import MobxFirebaseStore from 'mobx-firebase-store';

Define the property in which the array of tweets are stored:

const tweets_subkey = 'tweets';

Here’s what it looks like in the Firebase console:

Firebase database subkey

Create the store. Inside the constructor, connect to Firebase and create the store. MobXFirebaseStore accepts a reference to a Firebase database as its argument. Right below that, call super(store.fb) to make the store available inside the class via this.

export default class TweetStore extends MobxFirebaseStore {

  constructor(config) {
    const fbApp = Firebase.initializeApp(config);
    const store = new MobxFirebaseStore(Firebase.database(fbApp).ref());
    super(store.fb);
  }
  ...
}

allTweetsSubs() as you’ve known earlier, returns an array of subscriptions. In this case you only want to subscribe to a single subkey (tweets) and you want its data to be returned as a list (asList: true). Basically, it’s used to specify the subkey in your Firebase database that you want to subscribe to.

  
allTweetsSubs() {
  return [{
      subKey: tweets_subkey,
      asList: true
  }];
}

createTweet() uses Firebase’s push method to push the tweet object into the array. This creates a new item in the tweets array in Firebase which then triggers the subscriber to update the list of tweets for all the connected clients.

createTweet(tweet) {
  this.fb.child(tweets_subkey).push(tweet);
}

getTweets() returns the collection of tweets:

    
getTweets() {
  return this.getData(tweets_subkey);
}

resolveFirebaseQuery() is used for customizing the query used for fetching Firebase data. Here, the results are ordered according to their timestamp and only the 10 most recent tweets are being fetched. That said, Firebase still returns the records in ascending order that’s why you had to call reverse() on the TweetList component earlier to reverse the ordering.

  
resolveFirebaseQuery(sub) { 
  return this.fb.child(tweets_subkey).orderByChild('timestamp').limitToLast(10);
}

Add the Styles

Open the public/index.html file and add the following inside the <head>:


This uses picnic.css to add some default styling to make the project look good.

Next, create a src/index.css file and add the following:

body {
  margin: 0;
  padding: 0;
  font-family: sans-serif;
}

.tweets {
    margin-top: 30px;
}

.tweet {
    padding: 20px;
}

Conclusion

That’s it! In this tutorial you’ve learned how to use MobX to act as a data store for your Firebase data. As you have seen, using Firebase with MobX doesn’t completely change the way you interact with Firebase so you can still use your existing knowledge of the Firebase API. You can check out the code used in this tutorial in this Github repo.

About the Author:

Introduction to Data Binding with MobX

January 13th, 2017

Once you get past very simple applications, programming on the web can become a nightmare of event handling and notifications, where the state of an application is spread out among dozens of different text boxes, select boxes and similar components. This is one reason why Model/View/Controller architectures (MVC) have become pretty much de rigour (along with multiple variations on this theme) in web programming.

However, MVC also requires that when you change the model, the view will change in response. This is pretty easy to accomplish when there is a direct one-to-one relationship between a component and its associated value. Where things begin to fall apart is when multiple components are dependent upon the same set of values, or when changes in values change other values that have component dependencies. This is a behavior you see quite often with spreadsheets (and one reason why translating spreadsheets into web applications can be quite a headache).

Mobx and MVC

The Mobx library makes use of ES2015 and (with later version) ES2017 decorators in order to identify specific variables or objects and make them “observable”. What this means in practice is that the framework “keeps track” of these variables, and any time the variables change, then the a notifier is activated for handling the impacts of these changes.

An example of this can be seen in the following CodePen.

See the Pen MobX+React test by Kurt Cagle (@kurt_cagle) on CodePen.

This example is deliberately kept simple to illustrate the process. Here, you can change a person’s first or last name, or change their age by using a numeric input control. This data is kept within a particular data structure, when either part of the name is changed, a new variable called flippedName is calculated, which holds an alternative medium state (in this case the name given as “lastName, firstName”). Finally, if the age of the person is 18 or higher, the flipped name appears green – the person involved can participate in whatever activity is being supported. If the age is under 17, however, the flipped name turns red, and a warning message is posted.

This example is especially useful because the data is entangled – the dispay of the output text is dependent upon both the names and the age. Moreover, the input fields make it possible to update the model, showing a “round trip” type activity that is common with MVC type applications.

Dipping into the code, the first few lines take advantage of the Babel transpiler to implement the ES2017 decorator capabilities. Decorators are pre-process directives that perform “meta-operations” on code, and are in effect the equivalent of “aspect” programming used in languages like Java. These can be used to automate logging, to set up services from functions and, in the case of mobx, to identify and manage variables and objects to be watched.

Explore React Courses

The @observable decorator is syntactic sugar for the older ES2015 implementation mobx.observable(...). This is not a function in the traditional sense. Instead, observers act on functions and expressions of code prior to them actually being evaluated, deferring the actual evaluation until some context structures can be set up.

class Person {

@observable firstName;

@observable lastName;

@observable age:number;

constructor(_firstName,_lastName,_age){

this.firstName = _firstName;

this.lastName = _lastName;

this.age = _age;

this.bind("firstName");

this.bind("lastName");

this.bind("age");

}

@computed get flippedName() {return `${this.lastName}, ${this.firstName}` }

In this case, three properties of a given class are identified as being observable – firstName, lastName and age. This means that, when an instance of this is created, then the instance members will be observable.

The bind() function in this class is not directly mobx related. Instead, it establishes a simple binding between an input element with an id that has the same name as the variable in question. That way, if you change an input field, you also change the model, and by extension change any functionality that depends upon the variable being changed.

bind(prop,defaultValue){

document.querySelector(`#${prop}`).value = defaultValue!=null?defaultValue:this[prop];

document.querySelector(`#${prop}`).addEventListener("input", (evt)=>{this[prop] = evt.target.value});

}

An area where mobx really comes in handy is for those scenarios where you want to make computed properties. A computed property is one that has a dependency upon observable properties – when you change the observable, you also change the computed value. Here, the first and last names are inverted to create a “lastname, firstname” type string in this read-only getter. By using the @computed decorator, should the independent variables (firstName or lastName here) change, then the @computed getter is re-evaluated.

This is by itself actually a huge benefit that mobx provides. While for something like inverting name takes comparatively few cycles to perform, when you have complex structures, regular expressions, template strings, asynchronous calls or similar processes, not having to rerun a getter when nothing has changed can result in huge cycle and memory savings. The @computed decorator feature right here is well worth the price of admission to Mobx.

The mobx.autorun() decorator is one of the few that doesn’t have an associated @ property. It is one of the big workhorses of Mobx, however. Whenever an observable or computed property is changed mobx.autorun is called IF the enclosed expressions have dependencies upon those variables.

In the sample codepen, I define three “render” methods. The first displays the flipped label. The second changes the color of the inverted title from green to red if the age given is below 18, while the final method adds a warning beneath the input fields indicating when a person is too young to participate in the program.

There are three such mobx.autorun() statements, one that calls each of these functions respectively. When a user changes the first name using the input, the showLabel() and warn() functions are invoked. If they change the age, the redLabel() and warn() functions are invoked. Finally, if the last name is changed, then only showLabel() gets invoked. Why? The showLabel() function has a dependency on the first and last name, while warn() uses only the first name, and redLabel() has no dependency at all upon the last name.

The advantage of this should be obvious, especially with complex forms or applications. If a component is unchanged, then it should not be necessary to re-render it, especially when there are a lot of interdepencies acting upon that component.

In that respect, the relationship between MobX and React should be obvious. MobX creates a way to indicate when the broader (global) data model changes, notifying downstream functions when independent variables and automatically computing @computed values that can then reduce the overall computational cost. React maintains a data model at the component level, so that when state variables or attributes change, only those portions of the component dependent upon those changes gets updated.

This article focused on the basic functionality of mobx. A subsequent article will focus will look at how you can use mobx and react together to keep the total amount of unnecessary work for your application to a minimum.

Explore React Courses