Reactive d3 visualizations with React?

I recently set out to understand what it truly means to do reactive programming. React.js has ‘react’ in the name and with d3.js being the hotness that it is, I decided to create a reactive visualization with the two.

Repo

In reactive programming, when a reactive variable updates, so does the value of its dependencies. If your application was comprised of a long chain of reactive variables, imagine the benefits of such an architecture.

You could localize all updates to the state of your application to one place (or at the very least, fewer places). Whenever your app’s data updates, you can be sure that the state is current throughout the whole app. Truly reactive programming should also minimize unnecessary creation and changing of elements by only updating and creating when actually necessary.

Enter, power duo d3 and React.

React has elements built into it called `props` and `state` that are both reactive and immutable. e.g. if you update the `state` in one component, this triggers a re-rendering of that component and the components linked it by their `props`. A data change updates the entire app. Sounds pretty reactive.

D3 does something similar. When one changes the data used to build a visualization, the visualization changes! Also, pretty reactive sounding.

The combination of these two technologies sounds almost too perfect. Quick! Let’s elicit some ooohs and aaaahs.

My tools:

  • React Lifecycle methods: componentDidMount(), shouldComponentUpdate()
  • d3 selections
  • React props

Here are some issues that I ran into, misconceptions I had and subsequently revised:

  • Issue: At first I set out to update the data with which I wanted to draw the svg directly via the props of the component in which it was drawn. The outcome was a complete re-rendering of the svgs rather than an update to the data inside of the svgs. Instead of modifying the already drawn svgs, I was creating completely new ones. That’s not really reactive, although it certainly fooled me for a while, because the view was changing.
  • Fix: as data for drawing the svgs were being passed into the component I stored it in a single variable, which I mutated as the changes came in.
  • Issue: every time new props were received by my React component containing the d3 code, this caused an unnecessary re-rendering of that component. Normally an asset while creating applications with React, this was unneeded in my case as d3 would already update my app’s view.
  • Fix: update the data used to draw the svg in shouldComponentUpdate() and stifle a re-rendering by always returning false.
  • Issue: My d3 code seemed to always add more and more svgs to the DOM regardless of any clean-up code I wrote.
  • Fix: I didn’t understand how d3 selections work. It was understanding the difference between selectAll and select and how to use them together that allowed me to take advantage of d3's .enter(), .update(), .exit() lifecycle methods.