Creating Data Visualisations With D3 and React In 2020
Data visualisation and application technologies have evolved greatly over the past decade. Two of the most popular web-based technologies for this are D3.js and React.js and both began as separate projects in 2011. Now, after nearly 10 years, there is finally an elegant way to have these two technologies work together to deliver both an exciting data visualisation experience and sustainable development workflow.
D3 is an excellent library for rendering data visualisation — this should be preserved by separating D3 implementation from React.
Understanding this workflow is important for developers, designers and anyone involved with the process of creating data visualisations as it can help improve the experience and reduce the effort to create it. Having two workflows might seem contradictory to this second point and throughout this piece I will attempt to illustrate why this is not the case.
The fundamental difference between D3 and React
Both D3 and React provide their own DOM Manipulation API – adding, updating and deleting HTML. D3 offers life cycle events to match the DOM change operation (enter, update and exit) with method chaining syntax that is designed to directly alter the HTML elements. Whereby React provides an entirely different concept of a Virtual DOM with JSX syntax and React controls how this translates to the real HTML elements.
React and visual design evolution leads you to believe everything should be a React component
The powerful layer of abstraction from React provides an excellent development workflow such that parts of the page can be separated into individual components. This workflow also matches how web design has evolved from static full page designs into component based style guides – and more recently design systems. React has proved to be so useful at describing these modularised systems that the immediate reaction from developers was to bring other technologies such as D3 and abstract them into React components.
One approach would be using React to handle the DOM and styling and using D3 to only handle the math. This approach is what the evolution of React and visual design systems would lead us to believe is the most appropriate solution. However, it is not the case even though as of writing it is still quite a popular approach and many libraries use it today including the popular Recharts library. As these libraries will attest there are many benefits to writing all the DOM markup in JSX — such as being able to separate the parts of a data visualisation graphic as you would any other element on the page.
When pausing for a moment, this approach doesn’t actually align to how data visualisations are created — a visualisation cannot always be broken down into smaller parts as each part relates to each other much more closely than the other parts of a web page. There are also some significant downsides that involve needing to reimplement complex concepts in D3 such as data updates, transitions and animations. Another issue is that writing in JSX requires translating examples and references for D3 from an entirely different language — as most D3 examples are surprisingly described in the D3 method chaining syntax style and directly reference D3 APIs. All of this is to say that this approach is not respecting the fundamental difference between the two technologies.
How to separate D3 implementation from React
Another approach to working with D3 is to only render a root node in React and use D3 to control the visualisation with its own DOM Manipulation API. Data and events will still need to be transmitted between React and D3 and this can be achieved concisely with React Hooks.
The immediate benefits of this approach include each technology having a single responsibility, reference material for D3 is the same as the project code and any data visualisation presentation is possible with minimal code. This approach also makes the code more sustainable as D3 is decoupled from React and the two technologies are free to evolve independently with the effort to adopt new features from either very minimal on the project.
When adopting this approach it’s important to understand D3 elements can’t be separated in components in the same way they can in React. This is a side-effect of how the D3 lifecycle is designed, where richer experiences are built by describing together all the elements bound to the data. Each visualisation should be treated as a closed system. If React components are Lego bricks then D3 visualisations wrapped in React are light bricks.
Conclusion
As with all things in software development we should always strive to design systems and write code in a way that can adopt change as efficiently as possible. React and D3 have both evolved with each technology delivering excellent frameworks for their respective purposes. Projects will be able to adopt new features in each technology by respecting these frameworks with the independence they deserve.
Further reading
If you’re just starting out with D3 then I highly recommend Adam Janes on the David Walsh blog: 5 Crucial Concepts for Learning d3.js and How to Understand Them
Karol Stopya has a practical guide to separating D3 from React: https://link.medium.com/a9cjWGWhT9
This snippet by Alex Johnson does well to cover the pros and cons for different approaches to D3 and React: Working with React and D3 together · GitHub