React for Data Visualization
Student Login
  • Introduction

Optimizing React choropleth map rendering

This is a Livecoding Recap – an almost-weekly post about interesting things discovered while livecoding ?. Always under 500 words and with pictures. You can follow my channel here. New streams almost every Sunday at 2pm PDT. There’s live chat, come say hai ?

Yesterday was supposed to be all about cutting up a large-ish codebase into small chunks that are easier to explain step-by-step. I was a great plan, but it didn't quite happen.

Instead of doing that, I went down the rabbit hole of optimizing the choropleth map from Livecoding 24. Turns out my H1B visualization wasn't slow because the dataset was big. It was slow because the map re-renders 3,220 county polygons on every update. ?

Let me explain.

We started with this:


See how it takes 2 or 3 seconds to react when you click a button? That's bad.

And we finished with this:


Takes just a second. Still slow, but a lot better. The dataset to crunch is big after all. ?

Unfortunately, the paint flashing isn't useful to show you what's fixed. Looks like a parent component repaints and flashes everything. This is unfortunate and a potential clue for further improvements.

To make this 50% to 66% speed improvement, we did two things:

  1. Added shouldComponentUpdate to the County component
  2. Avoided doing _.find to find data on every polygon draw

I don't know which improvement had a bigger effect, but when you _.find in a N=290 array 3220 times, that's 933,800 function calls that you're making. Oops.

We fixed that by building a map beforehand. Like this:

const countyValueMap = _.fromPairs( => [d.countyID, d.value])

Then rendering County components in a loop, like this:

{ => (

That value prop used to be _.find(counties, {countyID:}) and that was dumb.

Lesson learned. Big-O matters even when you're just doing JavaScript.

Inside County, we added shouldComponentUpdate. I don't know why React wasn't able to optimize this for us, but it wasn't. Maybe because we were passing props in as functions? Probably.

The new County component looks like this:

class County extends Component {
shouldComponentUpdate(nextProps, nextState) {
const { zoom, value } = this.props;
return zoom !== nextProps.zoom || value !== nextProps.value;
render() {
// body from previous functional stateless version

We know for a fact that a county polygon only has to re-render when the map's zoom level changes or the value we're displaying changes. That enables the map to change size and the value to change polygon colors.

Excellent. Many lessons learned.

You can see the code for React + D3 choropleth maps on Github. It's embedded in a larger project, so there's some context-specific stuff, but the component itself is made to be pretty general.

About the Author

Hi, I’m Swizec Teller. I help coders become software engineers.

Story time πŸ‘‡

React+D3 started as a bet in April 2015. A friend wanted to learn React and challenged me to publish a book. A month later React+D3 launched with 79 pages of hard earned knowledge.

In April 2016 it became React+D3 ES6. 117 pages and growing beyond a single big project it was a huge success. I kept going, started live streaming, and publishing videos on YouTube.

In 2017, after 10 months of work, React + D3v4 became the best book I'd ever written. At 249 pages, many examples, and code to play with it was designed like a step-by-step course. But I felt something was missing.

So in late 2018 I rebuilt the entire thing as React for Data Visualization β€” a proper video course. Designed for busy people with real lives like you. Over 8 hours of video material, split into chunks no longer than 5 minutes, a bunch of new chapters, and techniques I discovered along the way.

React for Data Visualization is the best way to learn how to build scalable dataviz components your whole team can understand.

Some of my work has been featured in πŸ‘‡

Created bySwizecwith ❀️