Who loves charts? Everyone, right? There are lots of ways to create them, including a number of libraries. There’s D3.js, Chart.js, amCharts, Highcharts, and Chartist, to name only a few of many, many options.

But we don’t necessary need a chart library to create charts. Take Mobx-state-tree (MST), an intuitive alternative to Redux for managing state in React. We can build an interactive custom chart with simple SVG elements, using MST to manage and manipulate data for the chart. If you’ve attempted to build charts using something like D3.js in the past, I think you’ll find this approach more intuitive. Even if you’re an experienced D3.js developer, I still think you’ll be interested to see how powerful MST can be as a data architecture for visualizations.

Here’s an example of MST being used to power a chart:

This example uses D3’s scale functions but the chart itself is rendered simply using SVG elements within JSX. I don’t know of any chart library that has an option for flashing hamster points so this is a great example of why it’s great to build your own charts — and it’s not as hard as you might think!

I’ve been building charts with D3 for over 10 years and, while I love how powerful it is, I’ve always found that my code can end up being unwieldy and hard to maintain, especially when working with complex visualizations. MST has changed all that completely by providing an elegant way to separate the data handling from the rendering. My hope for this article is that it will encourage you to give it a spin.

Getting familiar with MST model

First of all, let’s cover a quick overview of what a MST model looks like. This isn’t an in-depth tutorial on all things MST. I only want to show the basics because, really, that’s all you need about 90% of the time.

Below is a Sandbox with the code for a simple to-do list built in MST. Take a quick look and then I’ve explain what each section does.

First of all, the shape of the object is defined with typed definitions of the attribute of the model. In plain English, this means an instance of the to-do model must have a title, which must be a string and will default to having a “done” attribute of false.

.model("Todo", {
  title: types.string,
  done: false //this is equivalent to types.boolean that defaults to false
})

Next, we have the view and action functions. View functions are ways to access calculated values based on data within the model without making any changes to the data held by the model. You can think of them as read-only functions.

.views(self => ({
  outstandingTodoCount() {
    return self.todos.length - self.todos.filter(t => t.done).length;
  }
}))

Action functions, on the other hand, allow us to safely update the data. This is always done in the background in a non-mutable way.

.actions(self => ({
  addTodo(title) {
    self.todos.push({
      id: Math.random(),
      title
    });
  }
}));

Finally, we create a new instance of the store:

const todoStore = TodoStore.create({
  todos: [
    {
      title: "foo",
      done: false
    }
  ]
});

To show the store in action, I’ve added a couple of console logs to show the output of outStandingTodoCount() before and after triggering the toggle function of the first instance of a Todo.

console.log(todoStore.outstandingTodoCount()); // outputs: 1
todoStore.todos[0].toggle();
console.log(todoStore.outstandingTodoCount()); // outputs: 0

As you can see, MST gives us a data structure that allows us to easily access and manipulate data. More importantly, it’s structure is very intuitive and the code is easy to read at a glance — not a reducer in sight!

Let’s make a React chart component

OK, so now that we have a bit of background on what MST looks like, let’s use it to create a store that manages data for a chart. We’ll will start with the chart JSX, though, because it’s much easier to build the store once you know what data is needed.

Let’s look at the JSX which renders the chart.

The first thing to note is that we are using styled-components to organize our CSS. If that’s new to you, Cliff Hall has a great post that shows it in use with a React app.

First of all, we are rendering the dropdown that will change the chart axes. This is a fairly simple HTML dropdown wrapped in a styled component. The thing to note is that this is a controlled input, with the state set using the selectedAxes value from our model (we’ll look at this later).