React+d3js ES6
Reusable dataviz & games using modern JavaScript
Swizec Teller
This book is for sale at http://leanpub.com/reactd3jses6
This version was published on 2016-04-05
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
© 2016 Swizec Teller
Tweet This Book!
Please help Swizec Teller by spreading the word about this book on Twitter!
The suggested tweet for this book is:
Gonna build me some cool stuff with #reactd3jsES6
The suggested hashtag for this book is #reactd3jsES6.
Find out what other people are saying about the book by clicking on this link to search for this
hashtag on Twitter:
https://twitter.com/search?q=#reactd3jsES6
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Why you should read React+d3.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What you need to know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
How to read this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
ES5 and ES6 versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Why React and d3.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Buzzword soup explained . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
JSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Visualizing data with React and d3.js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
The basic approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
The Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
The HTML skeleton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Structuring your React app . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Bootstrap your app into place . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Start with a basic component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Introduction
I wrote this book for you as an experiment. The theory we’re testing is that technical content works
better as a short e-book than as a long article.
You see, the issue with online articles is that they live and die by their length. As soon as you surpass
700 words, everything falls apart. Readers wander off to a different tab in search of memes and funny
tweets, never to come back.
This hurts my precious writer’s ego, but more importantly, it sucks for you. If you’re not reading,
you’re not learning.
So here we both are.
I’m counting on you to take some time away from the internet, to sit down and read. I’m counting
on you to follow the examples. I’m counting on you to learn.
You’re counting on me to have invested more time, effort, and care in crafting this than I would
have invested in an article. I have.
I’ve tried to keep this book as concise as possible. iA Writer estimates it will take you about an hour
to read React+d3.js, but playing with the examples might take some time, too.
Why you should read React+d3.js
After an hour with React+d3.js, you’ll know how to make React and d3.js play together. You’ll know
how to create composable data visualizations. You’re going to understand why that’s a good idea,
and you will have the tools to build your own library of reusable visualization parts.
Ultimately, you’re going to understand whether React and d3.js fit the needs of your project.
What you need to know
I’m going to assume you already know how to code and that you’re great with JavaScript. Many
books have been written to teach the basics of JavaScript; this is not one of them.
I’m also going to assume some knowledge of d3.js. Since it isn’t a widely-used library, I’m still going
to explain the specific bits that we use. If you want to learn d3.js in depth, you should read my book,
Data Visualization with d3.js¹.
¹https://www.packtpub.com/web-development/data-visualization-d3js
1
Introduction 2
React is a new kid on the block, so I’m going to assume you’re not quite as familiar with it. We’re
not going to talk about all the details, but you’ll be fine, even if this is your first time looking at
React.
The examples in React+d3.js ES6 edition are written in ES6 - ECMAScript2015. Familiarity with the
new syntax and language constructs will help, but I’m going to explain everything new that we use.
How to read this book
Relax. Breathe. You’re here to learn. I’m here to teach. I promise Twitter and Facebook will still be
there when we’re done.
Just you and some fun code. To get the most out of this material, I suggest two things:
1. Try the example code yourself. Don’t just copy-paste; type it and execute it. Execute it
frequently. If something doesn’t fit together, look at the full working project on Github here²,
or check out the zip files that came with the book.
2. If you already know something, skip that section. You’re awesome. Thanks for making this
easier.
React+d3.js is heavily based on code samples. They look like this:
var foo = 'bar';
Added code looks like this:
var foo = 'bar’;
foo += 'this is added’;
Removed code looks like this:
var foo = 'bar';
foo += 'this is added';
Each code sample starts with a commented out file path. That’s the file you’re editing. Like this:
²https://github.com/Swizec/h1b-software-salaries
Introduction 3
// ./src/App.jsx
class App …
Commands that you should run in the terminal start with an $ symbol, like this:
$ npm start
ES5 and ES6 versions
You are reading React+d3.js ES6 edition. Functionally, it’s almost the same as the ES5 version, but it
has a better file structure and some additional content.
You can read either version depending on which version of JavaScript you’re more comfortable with.
Keep in mind, the ES5 version isn’t getting further updates.
Both will teach you how to effectively use React and d3.js to make reusable data visualization
components.
Why React and d3.js
React is Facebook’s and Instagram’s approach to writing modern JavaScript front-ends. It encourages
building an app out of small, re-usable components. Each component is self-contained and only
knows how to render a small bit of the interface.
The catch is that many frameworks have attempted this: everything from Angular to Backbone and
jQuery plugins. But where jQuery plugins quickly become messy, Angular depends too much on
HTML structure, and Backbone needs a lot of boilerplate, React has found a sweet spot.
I have found it a joy to use. Using React was the first time I have ever been able to move a piece of
HTML without having to change any JavaScript.
D3.js is Mike Bostock’s infamous data visualization library. It’s used by The New York Times along
with many other sites. It is the workhorse of data visualization on the web, and many charting
libraries out there are based on it.
But d3.js is a fairly low-level library. You can’t just say “I have data; give me a bar chart”. Well, you
can, but it takes a few more lines of code than that. Once you get used to it though, d3.js is a joy to
use.
Just like React, d3.js is declarative. You tell it what you want instead of how you want it. It gives
you access straight to the SVG so you can manipulate your lines and rectangles at will. The issue is
that d3.js isn’t that great if all you want are charts.
This is where React comes in. For instance, once you’ve created a histogram component, you can
always get a histogram with <Histogram {...params} />.
Doesn’t that sound like the best? I think it’s pretty amazing.
It gets even better. With React, you can make various graph and chart components build off the same
data. This means that when your data changes, the whole visualization reacts.
Your graph changes. The title changes. The description changes. Everything changes. Mind = blown.
Look how this H1B salary visualization changes when the user picks a subset of the data to look at.
4
Why React and d3.js 5
Default H1B histogram
Why React and d3.js 6
Changes after user picks a data subset
React + d3.js: a powerful combination indeed.
Buzzword soup explained
We’re going to use a lot of buzzwords in this book. Hell, we’ve used some already. Most will get a
thorough explanation further on, but let me give you a quick rundown.
• Babel, a JavaScript transpiler that makes your code work on all browsers.
• ECMAScript2016, official name for the part of ES7 we’re getting in 2016
• ES5, any JavaScript features that existed before June 2015
• ES6/ECMAScript2015, any JavaScript features released as part of the new standard in June
2015 (think => and stuff)
• ES7, the standard we were promised for 2016, but also a catch-all for future JavaScript features
• fat arrows, a new way to define functions in ES6 (=>)
Why React and d3.js 7
• Git, a version control system. It’s pretty popular, you probably know it :)
• H1B, a popular type of work visa in the United States
• JSX, a language/syntax that lets you use <a href="/example"> as a native part of JavaScript
• Mustache, a popular way to write HTML templates for JavaScript code. Uses {{ ... }}
syntax.
• npm, most popular package manager for JavaScript libraries
• props, component properties set when rendering
• state, a local dictionary of values available in most components
• Webpack, a module packager for JavaScript. Makes it more convenient to organize code into
multiple files. Provides cool plugins.
JSX
We’re going to write our code in JSX, a JavaScript syntax extension that lets us treat XML-like data
as normal code. You can use React without JSX, but I think it makes React’s full power easier to use.
The gist of JSX is that we can use any XML-like string just like it is part of JavaScript. No Mustache or
messy string concatenation necessary. Your functions can return straight-up HTML, SVG, or XML.
For instance, the code that renders our whole application is going to look like this:
A basic Render
React.render(
<H1BGraph url="data/h1bs.csv" />,
document.querySelectorAll('.h1bgraph')[0]
);
Which compiles to:
JSX compile result
ReactDOM.render(
React.createElement(H1BGraph, {url: “data/h1bs.csv”}),
document.querySelectorAll(‘.h1bgraph’)[0]
);
As you can see, HTML code translates to React.createElement calls with attributes translated into
a property dictionary. The beauty of this approach is two-pronged: you can use React components
as if they were HTML tags and HTML attributes can be anything.
You’ll see that anything from a simple value to a function or an object works equally well.
Why React and d3.js 8
I’m not sure yet whether this is better than separate template files in Mustache or something similar.
There are benefits to both approaches. I mean, would you let a designer write the HTML inside
your JavaScript files? I wouldn’t, but it’s definitely better than manually +-ing strings or Angular’s
approach of putting everything into HTML. Considerably better.
If you skipped the setup section and don’t have a JSX compilation system set up, you should do that
now. You can also use the project stub that came with your book.
Visualizing data with React and d3.js
Welcome to the main part of React+d3.js. I’m going to walk you through an example of building a
visualization using React and d3.js.
We’re going to build a subset of the code I used to visualize the salary distribution of H1B workers³
in the United States software industry.
H1B salary distribution for engineers in California
If you skipped the environment setup section, make sure you have the following dependencies:
• d3.js
• React
• Lodash
You should also have some way of running a static file server, and a way to compile JSX into pure
JavaScript. I like having a small node.js server that supports hot loading via Webpack, and I like to
compile with Babel.
³http://swizec.github.io/h1b-software-salaries/#2014-ca-engineer
9
Visualizing data with React and d3.js 10
We’re going to put all of our code in a src/ directory and serve the compiled version out of static/.
A public/data/ directory is going to hold our data.
Before we begin, you should copy our dataset from the stub project you got with the book. Put it in
the public/data/ directory of your project.
The basic approach
Because SVG is an XML format that fits into the DOM, we can assemble it with React. To draw a
100px by 200px rectangle inside a grouping element moved to (50, 20) we can do something like
this:
A simple rectangle in React
render() {
return (
<g transform="translate(50, 20)">
<rect width="100" height="200" />
</g>
);
}
If the parent component puts this inside an <svg> element, the user will see a rectangle. At first
glance, it looks cumbersome compared to traditional d3.js. But look closely:
A simple rectangle in d3.js
d3.select("svg")
.append("g")
.attr("transform", "translate(50, 20)")
.append("rect")
.attr("width", 100)
.attr("height", 200);
The d3.js approach outputs SVG as if by magic, and it looks cleaner because it’s pure JavaScript. But
it’s more typing and more function calls for the same result.
Well, actually, the pure d3.js example is 10 characters shorter. But trust me, React is way cooler.
Despite appearances, dealing with the DOM is not d3.js’s strong suit. Especially once you’re drawing
a few thousand elements and your visualization slows down to a leisurely stroll… if you’re careful.
Updating DOM with d3 takes a lot of work: you have to keep track of all the elements you’re
updating, the ones that are new, what to remove, everything. React does all of that for you. Its
Visualizing data with React and d3.js 11
purpose in life is knowing exactly which elements to update, and which to leave unchanged. Update
it and forget it. Amazing.
We’re going to follow this simple approach:
• React owns the DOM
• d3 calculates properties
That lets us leverage both React and d3.js for what they’re best at.
The Architecture
To make our lives easier, we’re going to use a flow-down architecture inspired by Flux. All state is
stored in one place - the main component - and data flows down via component properties. Changes
travel back up the hierarchy via callbacks.
Our approach differs from Flux (and Redux) in that it doesn’t need any extra code, which makes it
easier to explain. The downside is that our version doesn’t scale as well as Flux would.
If you don’t know about Flux or Redux, don’t worry; the explanations are self-contained. I only
mention them here to make your Googling easier and to give you an idea of how this approach
compares. I explain Redux in more detail in the Animating with React, Redux, and d3 chapter.
Visualizing data with React and d3.js 12
The basic architecture
The idea is this:
• The Main Component is the repository of truth
• Child components react to user events
• They announce changes using callbacks
• The Main Component updates its truth
• The real changes flow back down the chain to update UI
This might look roundabout, but I promise, it’s awesome. It’s better than worrying about parts of
the UI going out of date with the rest of the app. I could talk your ear off with debugging horror
stories, but I’m nice, so I won’t.
Visualizing data with React and d3.js 13
Data flows down
Having your components rely just on their properties is like having functions that rely just on their
arguments. Given the same arguments, they always render the same output.
If you want to read about this in more detail, Google “isomorphic JavaScript”. You could also search
for “referential transparency” and “idempotent functions”.
Either way, functional programming for HTML. Yay!
The HTML skeleton
We’re building our interface with React, but we still need some HTML. It’s going to take care of
including files and giving our UI a container.
Make an index.html file that looks like this:
Visualizing data with React and d3.js 14
HTML skeleton
<!-- ./index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>How much does an H1B in the software industry pay?</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3\
.3.5/css/bootstrap.min.css" integrity="sha512-dTfge/zgoMYpP7QbHy4gWMEGsbsdZeCXz7\
irItjcC3sPUFtf0kuFbDz/ixG7ArTxmDjLXDmezHubeNikyKGVyQ==" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="h1bgraph"></div>
</div>
<script src="static/bundle.js"></script>
</body>
</html>
These 20 lines do everything we need. The <head> sets some Bootstrap-recommended meta
properties and includes Bootstrap’s stylesheet. This is a good approach for when you only need
Bootstrap’s default styles and don’t want to change anything. We’ll use require() statements to
load our own stylesheets with Webpack.
The <body> tag creates a container and includes the JavaScript code. We didn’t really need a <div>
inside a <div> like that, but I like to avoid taking over the whole .container with React. This gives
you more flexibility to add static content.
At the bottom, we load our compiled JavaScript from static/bundle.js. This is a virtual path
created by our dev server, so it doesn’t point to any actual files.
Structuring your React app
As you can guess from the architecture chapter, we’re going to structure our app into components.
Deciding what to put into one component and what into another is one of the hardest problems in
engineering.
Entire books have been written on the topic, so here’s a rule of thumb that I like to use: If you have to
use the word “and” to describe what your component does, then it should become two components.
Visualizing data with React and d3.js 15
Once you have those two components, you can either make them child components of a bigger
component, or you can make them separate. The choice depends on their re-usability.
For instance, to build our H1B histogram visualization, we are going to build two top-level
components:
• H1BGraph, which handles the entire UI
• Histogram, which is a passive component for rendering labeled histograms
Histogram is going to be a child of H1BGraph in the final hierarchy, but we might use it somewhere
else. That makes it a good candidate for a stand-alone component.
Other components such as the mean value dotted line, filter controls, and title/description meta
components are specific to this use-case. We’ll build them as child components of H1BGraph.
Building them as separate components makes them easier to reason about, reusable locally within
H1BGraph, and easier to write tests for.
We’re not going to write tests here, though. That’s a topic for another book. Right now, we’re going
to focus on React and d3.js.
Each component will have its own folder inside src/components/, or its parent component, and at
least an index.jsx file. Some will have style definitions, child components, and other JavaScript
files as well.
In theory, each component should be accessible with require('./MyComponent'), and rendered
with <MyComponent {...params} />. If a parent component has to know details about the imple-
mentation of a child component, something is wrong.
You can read more about these ideas by Googling “leaky abstractions”⁴, “single responsibility
principle”⁵, “separation of concerns”⁶, and “structured programming”⁷. Books from the late 90’s
and early 2000’s (when object oriented programming was The Future (tm)) are the best source of
[curated] info in my experience.
Bootstrap your app into place
Let’s start by bootstrapping our app into place. We’re going to make a simple src/index.jsx file –
we set that to be our main entry file in the environment section – and an empty H1BGraph component
that renders an SVG element.
We start by importing React, ReactDOM, and H1BGraph.
⁴https://en.wikipedia.org/wiki/Leaky_abstraction
⁵https://en.wikipedia.org/wiki/Single_responsibility_principle
⁶https://en.wikipedia.org/wiki/Separation_of_concerns
⁷https://en.wikipedia.org/wiki/Structured_programming
Visualizing data with React and d3.js 16
Import main dependencies
// ./src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import H1BGraph from './components/H1BGraph';
React is, well, React. We need it for just about everything. ReactDOM is React’s DOM renderer, which
is new in v0.14. Rendering got split out of base React so that it’s easier to build React apps for different
render targets like canvas, WebGL, native mobile, etc. H1BGraph is going to be our main component.
We’re using ES6-style imports instead of require() because it gives us greater flexibility to import
only the parts we want and it reads like a normal English sentence in most common-use cases. You’ll
see this play out in future examples.
The second argument must be a string even if you’re importing a library.
The main entry point for the app is also a good place to define any convenience helper functions
that should be available globally but aren’t big enough or important enough to make a new library
for. We’ll add capitalize and decapitalize to the String class. There are libraries out there that
do this, but there’s no need to add an entire string manipulation library to our codebase if all we
need are two functions.
Define two string helpers
// ./src/index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import H1BGraph from './components/H1BGraph';
String.prototype.capitalize = function() {
return this.charAt(0).toUpperCase() + this.slice(1);
}
String.prototype.decapitalize = function () {
return this.charAt(0).toLowerCase() + this.slice(1);
}
Now we’ll be able to capitalize and decapitalize any string in our codebase with a call like "some
thing".capitalize(). We’re going to use this in the Title and Description meta components. We
define them here because they change the global String class, and it would be odd if that happened
deep down in a child component… maybe we should’ve just avoided changing built-in classes.
All we need now is to render H1BGraph into the page.
Visualizing data with React and d3.js 17
Render H1BGraph onto page
// ./src/index.jsx
ReactDOM.render(
<H1BGraph url="data/h1bs.csv" />,
document.querySelectorAll('.h1bgraph')[0]
);
This tells React to take control of the HTML element with class h1bgraph – a <div> inside the main
container in our case – and render the H1BGraph component. We used ReactDOM.render because
we’re rendering for and in a browser. Other renderers exist, but they’re not important right now.
You can think of this function call as a “Give me a Thing That Does Stuff”. It doesn’t have to stand
on its own. You could wrap it in a jQuery plugin, use it inside a Backbone or Angular view, or in
whatever else you’re already used to. That’s how you can make a gradual transition towards React
that doesn’t force you to throw existing code away.
If you’ve kept npm start running in the background, it should now complain that components/H1BGraph
doesn’t exist. Let’s fix that and get an empty <svg> element rendering.
Start with a basic component
All of our components are going to start the same way – some imports, a class with a render()
method, and a default module export. That’s the minimum we need in <component>/index.jsx to
define a component that doesn’t break our build.
Right now, the main entry file tries to import and render H1BGraph, but it doesn’t exist yet. Let’s
start a new file in src/components/H1BGraph/index.jsx.
Basic imports
// ./src/components/H1BGraph/index.jsx
import React, { Component } from 'react';
import d3 from 'd3';
We import React and a base Component class. We have to import React even if we don’t use it
explicitly because Webpack throws a “React not defined” error otherwise. We’ll use the Component
class to build our own components off of.
We also import d3 because we’ll use it to load data later.
Visualizing data with React and d3.js 18
Empty H1BGraph component
// ./src/components/H1BGraph/index.jsx
import React, { Component } from 'react';
import d3 from 'd3';
class H1BGraph extends Component {
render() {
return (
<div>
<svg>
</svg>
</div>
);
}
}
Then we define a component that renders an empty <svg> tag inside a <div>. A component must
have at least a render() function; otherwise, React throws an error when it tries to render. With
v0.14 we also got stateless functional components, which are essentially just the render() function.
They don’t feature in this Histogram example, but you can see some in the animation chapter.
We’re using ES6’s concept of classes and class inheritance to extend React’s basic Component,
which we imported earlier. This is widely accepted as more readable than JavaScript’s old/standard
prototypical inheritance.
You can still use React.createClass if you want. It works just fine and is equivalent to class X
extends Component.
Export H1BGraph
// ./src/components/H1BGraph/index.jsx
import React, { Component } from 'react';
import d3 from 'd3';
class H1BGraph extends Component {
render() {
return (
<div>
<svg>
</svg>
</div>
);
}
Visualizing data with React and d3.js 19
export default H1BGraph;
In the end, we export H1BGraph so other parts of the codebase can import it. We define it as the
default export because this particular file only exports a single class.
If we had multiple things to export, we’d use named exports. They look like this: export { Thing
}. You can also define the Thing anonymously when exporting, like this: export function Thing
() { // ... }.
Using default exports makes our components easier to import - import Thing from 'file'. To
import named exports, you have to specify them inside curly braces: import { Thing1, Thing2 }
from 'file'.
Hot reloading and continuous compilation should have done their magic by now, and you should see
an empty <svg> element in your page. You have to keep npm start running and a browser window
pointing to localhost:3000 for that.
Congratz! You just made your first React component with ES6 classes. Or at least the first in this
book. You’re awesome!
Here’s what happens next:
1. We’ll make H1BGraph load our dataset
2. Build a Histogram component
3. Add dynamic meta text descriptions
4. Add some data filtering