Rendering folder trees in React

Over the past ~2 years of building web UIs in React, I’ve found myself turning back to this One Weird Trick when it comes to dealing with nested folder trees (or similar problems). I put together a little example to use as a starting point.

The end result is embedded below and the code is here.

I’ll dive into some of the reasoning below.

Keeping recursion separate

With a nested structure like this, it’s common to use recursive logic to dig through the children. You might use recursion to render the expanded tree, find a folder by ID, or update a folder’s data in memory. These operations can be complex, heavy, and not the most readable in code, so it would be nice to keep the touch-points with complex recursive logic as tidy as possible.

Take rendering, for example. One approach would be to do the recursion straight in the render(). Maybe you could define a component that would render a folder and its children recursively, sorta like this:

This totally works, and looks pretty nice, but I actually prefer a different approach.

Whenever possible, it’s nice to avoid having complicated logic tied up directly in rendering. In the example above, the recursive logic is simple, but in a real world application it could grow in complexity fast. If you need to reuse the folder tree or present it in a slightly different way, you’re forced to either use the existing component (maybe going in and adding some options in that component to support different UI needs, which could turn unwieldy) or create a new component, in which case you’d have to rewrite the recursive logic to deal with the nested structure.

Also, by recursing through the entire tree every time render() is invoked, you could be making it harder on yourself to keep performance in check. Is it ever possible you’d want to re-render without recursing through the whole tree? Perhaps, but it’s hard to explore those options when they’re so tied up in each other. This actually isn’t a huge deal (no need for premature optimization), and there are different ways to solve this problem. But keeping the recursion totally separate from the render eliminates this problem altogether and gives you more control over when and how often the most complicated logic is being executed.

Flattening the tree to prepare for rendering

I’ve grown to really like the approach of processing the nested data structure before rendering. If you flatten the tree, calculating and storing all necessary data for display, rendering becomes as simple as:

In the example I’ve linked at the top of this post, the flattening function calculates and stores two extra pieces of data along with the given folder data.

1. Indent level

If we want to represent a folder tree with a flat array, we need to know what level deep the folders are so we can display them with an appropriate indent.

2. Path to folder

Keeping track of the path to the corresponding folder in the nested or “true” tree data makes lookup quick and easy later on.

Here’s an example of the data representing a nested folder tree:

And the resulting “flattened” data:

Pulling out the recursion into a separate, pure function to create a flat, dumb structure has a lot of benefits. We are in complete control of when we perform the most expensive operations in the component. We only have to recurse when we deem it necessary. It means our render()s don’t have to be quite as smart. It simplifies the process of creating different UIs to present the data in different ways.

Check out the code! (ノ◕ヮ◕)ノ*:・゚✧

Leave a Reply

Your email address will not be published. Required fields are marked *