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
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
When we open up
src/Chart/Axis.jsx, we should see three basic React components.
Similar to how
d3.axisLeft() are different methods, we want to split out
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
The other two components,
AxisVertical, are specific
Axis implementations. Let's start by fleshing out
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
.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.