This video is available to students only

Drawing our peripherals in React, take two

We learn an alternate, less hacky solution for creating an Axis component that lets React do all of the rendering.

Drawing our peripherals, take two#

Now that we've shown how easy it is to plug basic d3 code into React, let's talk about why it's not a good idea.

React uses a fancy reconciliation algorithm to decide which DOM elements to update. It does this by creating a virtual DOM and diffing against the real DOM. When we mutate the DOM outside of React render methods, we're removing the performance benefits we get and will unnecessarily re-render elements.

Short-cutting around React render methods also makes our code less declarative. Usually, you can depend on the resulting DOM to closely align to any JSX you see in a component's render method. When you come back to a component you wrote a few months ago, you'll thank yourself for making the output obvious.

In a pinch, using React to create a wrapper element to modify with d3 (like we just did) will do. You might need to do this for special cases, like animating an arc. But try to lean towards solely creating elements with React and using d3 as more of a utility library. This will keep your app speedy and less "hacky".

Even without its DOM modifying methods, d3 is a very powerful library. In fact, we created most of our timeline without needing to re-create a d3 generator function. For example, creating a d string for our Line component would have been tricky without d3.line().

But how does this look in practice? Let's re-create our Axis component without using any axis generators.

Switch your Axis import in src/Timeline.jsx to use the Axis file.

When we open up src/Chart/Axis.jsx, we should see three basic React components.

Similar to how d3.axisBottom() and d3.axisLeft() are different methods, we want to split out x and y axes into different components. This will keep our code clean and prevent too many ternary statements.

The first component is a directory component that grabs the chart dimensions and renders the appropriate Axis, based on the dimension prop.

The other two components, AxisHorizontal and AxisVertical, are specific Axis implementations. Let's start by fleshing out AxisHorizontal.

Since we're not using a d3 axis generator, we'll need to generate the ticks ourselves. Fortunately, many of the methods d3 uses internally are also available for external use. d3 scales have a .ticks() method that will create an array with evenly spaced values in the scale's domain.

We can see this in action if we console.log(scale.ticks()).


By default, .ticks() will aim for ten ticks, but we can pass a specific count to target. Note that .ticks() will aim for the count, but also tries to create ticks with meaningful intervals: a week in this example.

The number of ticks we want will depend on the chart width, though — ten ticks will likely crowd our x axis. Let's aim for one tick per 100 pixels for small screens and one tick per 250 pixels for wider screens.


This page is a preview of Fullstack D3 Masterclass

No discussions yet