How to Use Recursive Components in React to Display Deeply Nested Data

This doesn’t have to be a nightmare to build

I’m sure you’ve experienced the sudden nightmare when you make an API call and the data that gets returned contains an array in it with more data. Then you open that array and it’s filled with more arrays with more data. And then each one of those data elements is another array with more data!

Here’s the Pathetic News Network app from the picture above.

Here’s an example of the data we’re working with. It’s my project from last week to display articles and comments from the Hacker News API.

That link will display all the comments for one article. As you can see in the “children” array, each comment has another “children” array with comments under it that leads to another “children” array of comments for that comment, and so on.

Visual Representation of HN API

That doesn’t have to make you crazy. In fact, it should make you happy to find your data in a set like that; very standardized, each sub-element using the same data structure as the element above it, and no extra API calls to get more data, because it’s all in one result!

Here’s another example. Microsoft ended up cutting off this data, but this is (was) the Bing API for Covid-19 data that they released a few months ago:

Still hurts that they cut off the feed

It starts with “areas” being countries, then there’s an “areas” array under that for states, then another “areas” array for counties, etc… It was scary at first, but then fun and inviting once you get to playing with it using recursion.

Which is what we’re going to do now using the Hacker News API.

Here’s the component for each article:

That just prints the list of article titles from the main API call and calls a component, NewsInfo to list the specifics.

So in this picture it’s just the line that says “Show HN: Learn coding to become a software engineer”

Then the NewsInfo component will display the “Created 06–04–20…” line below it. Here’s that component:

See how the word “comments” on that line is a link to expand or contract the actual comments for that article? That’s when it does the fetch to get the individual article and the “children” arrays under it.

It also displays another new component we’ve called “Comment” and this is the one we’ll be using recursion on to nest. In case you’re wondering why I’ve basically just glossed over all this stuff is because it’s just pretty standard React component building, nothing too fancy.

Here’s what we came to see (only 600 words into the article):

What’s this diminutive, elegant sum-b doing that’s so great? Well, it’s checking to see if there are more comments underneath the current comment, and if there are, then it calls itself to output those comments as well using the same component and same comment structure as the one that called it the first time!

How’s that for a Happy Ending?

Let’s see how it works!

The first thing it’s doing is taking in two parameters as props,

The “comment” prop comes from the fetch we just did to get all comments for the article, and the “postAuthor” prop we’re passing from the original article. It’s specifically so that if the commentor happens to be the person who wrote the article, we can highlight them in some way. In our example we use a pencil icon next to their info line.

Here’s the recursion:

We made this a function component just because it doesn’t really do anything. There’s no real reason to use a state object, but we are going to want to add a toggle so that the user can choose to show or hide each comment if they like.

To do that, we use a “State Hook” to emulate a state object without actually having to create one.

We’re setting a boolean variable called “showChildren” and defining a method called “setShowChildren” that we’ll use to manipulate it. Then on the right side we’re initializing showChildren to “true” because we want to start out with all comments visible and let the user decide whether to hide them or not.

Then this part:

creates a variable called “nestedComments” that maps the “children” array in the API results to ..what?!..more of this same Comment component! It does that by sending it the same original postAuthor prop and a new “comment” prop that is the current “comment.children” element, which we have also called “comment”.

Still with me? Good! Because if it loops through again and finds another “children” array, it’s going to do the same thing! And it’s going to keep doing the same thing until there are no more children arrays and no more comments.

But we still haven’t rendered the top comment yet! That’s what this mess is:

Once again, we’re back to just regular react components. Notice how I’ve added an invisible div there to call the useState hook we setup earlier?

When you click that div it calls the useState method we named “setShowChildren” to toggle our “showChildren” boolean. It didn’t have to be a toggle, because once showChildren is false, then we won’t have an invisible div there to click any more.

That’s why you can see we provided the same functionality on the second line, when the user clicks the commentor’s info line.

Then, once the original comment has been displayed to the screen, we call the recursive variable we made to display under it any other comments that have been made to that comment:

That’s it! That’s how you do it.

The only other note of interest is how I added an ‘avatar’ to each commentor’s info line. I’m sure Hacker News members can have their own personal avatars, but since they’re not included in the API results I simply used the RoboHash API to create one based on their user name.

All that styling is what I used to make sure nested comments indented well enough. All that can be moved to a css stylesheet or a css object if that’s what you’re into.

Here’s a live verion:

Here’s the github repo for the whole app:

and here’s where you can pay for me some programming lessons!

Thenk yew



4a 75 73 74 20 61 6e 6f 74 68 65 72 20 63 6f 6d 70 75 74 65 72 20 6e 65 72 64 20 77 69 74 68 20 61 20 62 6c 6f 67

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store

4a 75 73 74 20 61 6e 6f 74 68 65 72 20 63 6f 6d 70 75 74 65 72 20 6e 65 72 64 20 77 69 74 68 20 61 20 62 6c 6f 67