Best Practice for Integrating D3js in React
Tags: react, d3js
Published: 2019-04-22 08:44:49

---
title: Best Practice for Integrating D3js in React
published: true
description: Creating custom data visualizations within a larger web app can become complicated when using D3.js since both React and and D3 want to handle DOM manipulation.
tags: [React, D3js]
canonical_url: https://warrenwong.org/best-practice-for-integrating-d3js-in-react/
---

Creating custom data visualizations within a larger web app can become complicated when using D3.js since both React and and D3 want to handle DOM manipulation. D3 also includes the libraries to fetch and parse data, which maybe handled by React and then passed into the visualization component through props.

One of the better articles I've found regarding this is Elijah Meeks' [Interactive Applications with React & D3](https://medium.com/@Elijah_Meeks/interactive-applications-with-react-d3-f76f7b3ebc71). He also has a chapter that has a bit more breadth of examples in chapter 9 of his [D3.js in Action](https://www.manning.com/books/d3-js-in-action) book.

Meeks lays out the two common ways people usually integrate the two libraries which are basically to use React as a wrapper for the D3 visualization or using React to create each element in the `svg`. His preferred way is the latter because he likes to take advantage of the React lifecyle methods to update the elements of the visualization. The former example would require writing extra methods that the React lifecycle methods would then invoke whenever there's an update in the data or screen size, etc.

The obvious advantage of separating out the React and D3 is that you can stick fairly closely to any D3 example. You can also have D3 manage loading all the data that it's relying on.

I'm currently working with a team that isn't very familiar with front end development and React (which might be uncommon, since Meeks argues for using React for handing element creation since his team is more familiar with React than D3) thus the advantages of having use of React's lifecycle methods create the elements will be lost by having most of the team confused by intermingled logic.

Since I'm writing this in 2019, I want to have an example written with a Function Component utilizing Hooks rather than lifecycle methods.

You can follow along with his blog post mostly, but if you need his code example with useEffect, take a look below.

**BarChart.js**

```jsx
import { max } from "d3-array";
import { scaleLinear } from "d3-scale";
import { select } from "d3-selection";
import React, { useEffect } from "react";

const BarChart = ({ data, size }) => {
  let node;
  const createBarChart = node => {
    const dataMax = max(data);
    const yScale = scaleLinear()
      .domain([0, dataMax])
      .range([size[1], 0]);

    select(node)
      .selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .data(data)
      .style("fill", "#fe9922")
      .attr("x", (d, i) => i * 25)
      .attr("y", d => size[1] - yScale(d))
      .attr("height", d => yScale(d))
      .attr("width", 25);
  };

  useEffect(() => {
    createBarChart(node);
  });
  return <svg ref={n => (node = n)} height="500" width="500" />;
};

export default BarChart;
```

The main differences here from the one that Meeks has in his post are:

- `useEffect` invokes `createBarChart` and this is in effect the same result as invoking this function in both `componentDidMount` and `componentDidUpdate`.
- I don't know why he appends all the `"rect"` elements then removes them, then adds them again. If anyone knows why, please let me know. I've chosen not to do that and instead call the `data` method immediately after `append("rect")`.
- I don't worry about the `this` context since the `node` is assigned to the `node` variable inside the `BarChart` function closure.
- The lambda in `useEffect` can also return a function to do cleanup. Since the `svg` element is rendered by React, this isn't necessary for this case.
- The contents of the `createBarChart` function can all just be in the lambda inside `useEffect`.

The `WorldMap.js` example is even more straight-forward, even though he now uses React to render each individual element in the `svg`.

**WorldMap.js**

```jsx
import { geoMercator, geoPath } from "d3-geo";
import React from "react";
import "./App.css";
import worlddata from "./world"; // geojson

const WorldMap = () => {
  const projection = geoMercator();
  const path = geoPath().projection(projection);
  const countries = worlddata.features.map((d, i) => (
    <path key={`path${i}`} d={path(d)} className="countries" />
  ));

  return (
    <svg width={500} height={500}>
      {countries}
    </svg>
  );
};

export default WorldMap;
```

This is pretty interesting that we don't need a reference to the `svg` node since we are using React to create the elements directly in the parent `svg` element returned by the `WorldMap` React component. I have to say that this does appeal to me. I can compose the visualization just like any other React component, but there are drawbacks. The performance of animations seems to be quite slow compared to having D3 handle that.

_Originally published at [warrenwong.org](https://warrenwong.org/best-practice-for-integrating-d3js-in-react) on March 11, 2019._