Recursion in React: Render Comments with Nested Children
Recursion is a programming technique that has a lot of useful applications when building software. In this article, we'll explain the concept of recursion and how you can put it to good use in a React application.
As an example, we'll be building a React component that has the data structure of a comments section that displays both parent comments and their children.
Let's get started!
Table of Contents
What is Recursion?
Before we jump into a React use-case for recursion, it will help to have a good understanding of what recursion is in the realm of computer science.
Recursion is a technique for solving a problem where the final solution depends on several solutions to smaller instances of the same problem. In computer science, this is usually applied by a function being called by itself repeatedly. This allows you to write code that is succinct and elegant.
In the simplest terms possible, recursion is when a part of your code calls itself.
To serve as an example, take a simple while
loop like the one below:
let count = 5
while (count > 0) {
console.log(count--)
}
This is an example of an iterative function as it logs each value until the count
value is no longer greater than zero.
We can achieve the same result with a recursive function. Here is a recursive version of the while
loop:
function countdown(count) {
if (count > 0) {
console.log(count)
return countdown(count - 1)
} else {
return count
}
}
countdown(5)
Notice how the countdown()
function calls itself when the count
is greater than zero? Unlike the while
loop from before, this function avoided modifying the state of any variables and still took advantage of the value
passed to it as a parameter. Instead, the function repeatedly called itself until the count
value given to the function was not greater than zero.
The results of both the while
loop and recursive countdown()
function were the same, but the way they got to the result was completely different.
Pretty cool right?
Hopefully, that gave you a better understanding of how recursion works. In the next section, we'll show you how to use recursion in a React application.
Using Recursion in React
A great example of where recursion can be put into practice is a comments section on a website like Reddit or Hacker News. Each parent comment has one or more children comments nested below them. And each of those children's comments can have one or more children of their own. The layers can go on for multiple generations of comments, much like a family tree.
How would we go about rendering that in a React application when each comment section has a variable number of parent and children comments? Your code needs to be able to dynamically handle the variable number of both parent and children comments.
First, let's figure out what the data would look like that we would be working with.
Let's assume it'll look like this:
const commentData = {
title: "Fake article title.",
author: "grzm",
comments: [
{
id: 1,
text: "Example comment here.",
author: "user2",
children: [
{
id: 2,
text: "Another example comment text.",
author: "user3",
children: [
{
id: 3,
text: "Another example comment text.",
author: "user4",
children: []
}
]
}
]
},
{
id: 4,
text: "Example comment here 2.",
author: "user5",
children: []
}
]
}
This is some data for a fake article with the title "Fake article title.".
The comments are an array of objects, all of which are parent comments. Each parent comment has an array of children
comments. And each of those children can also have their own children.
Given that data, we want to stack the comments with the parent on top and their children below them like you see on Reddit or Hacker News.
And each child comment should be nested inside its parent with some margin
styling set to the left and right so the comments appear hierarchical on the page and are easy to read.
Here's a function that will recursively render each parent comment and its children:
function Comment({ comment }) {
const nestedComments = (comment.children || []).map(comment => {
return <Comment key={comment.id} comment={comment} type="child" />
})
return (
<div style={{"marginLeft": "25px", "marginTop": "10px"}}>
<div>{comment.text}</div>
{nestedComments}
</div>
)
}
This is a function we would place inside a React component and have it render each parent comment that is stored in our data.
It takes a parent comment object for a parameter and maps() each of the parent's children comments. When it's done, it stores the results in an array of components nested inside each other called nestedComments.
The Comment()
function then returns a <div>
element with the parent comment and all of its children (also <div>
elements) stacked inside of it via the {nestedComments}
line of code.
To use the function, we need to place the Comment
function directly into a React component that we export to either render as a page or be used in another page.
Here's what it would look like:
function App() {
return (
<div>
{
commentData.comments.map((comment) => {
return (
<Comment key={comment.id} comment={comment} />
)
})
}
</div>
)
}
export default App
In our React component, we map()
over each parent comment from our commentData
object data and run the Comment()
function for each one. In this case, our fictional article only has two parent comments so the Comment()
function is called twice.
It may help to open the developer tools in your browser and check out how the comments are rendered in the DOM (Document Object Model). You'll notice that each comment is its own <div>
with each child nested inside its parent's <div>
.
For your reference, here is the full code for what we did in this article:
import React from "react"
const commentData = {
title: "Fake article title.",
author: "grzm",
comments: [
{
id: 1,
text: "Example comment here.",
author: "user2",
children: [
{
id: 2,
text: "Another example comment text.",
author: "user3",
children: [
{
id: 3,
text: "Another example comment text.",
author: "user4",
children: []
}
]
}
]
},
{
id: 4,
text: "Example comment here 2.",
author: "user5",
children: []
}
]
}
function Comment({ comment }) {
const nestedComments = (comment.children || []).map(comment => {
return <Comment key={comment.id} comment={comment} type="child" />
})
return (
<div style={{"marginLeft": "25px", "marginTop": "10px"}}>
<div>{comment.text}</div>
{nestedComments}
</div>
)
}
function App() {
return (
<div>
{
commentData.comments.map((comment) => {
return (
<Comment key={comment.id} comment={comment} />
)
})
}
</div>
)
}
export default App
The code above has everything combined into one file:
- the
commentData
object for a fake article that holds the data for the comments - the
Comment()
function that recursively renders each parent and child comments - the final
App
component that is exported from the file
To keep this article short, the code only shows you how to render comments in a way that is recursive and nested, but there's a lot you can add on to this in terms of styling and functionality.
For example, comments sections usually display the username of the person who made the comment and have a way for you to upvote or downvote comments. And there is a lot you would need to add in terms of CSS styling.
But, we will leave those things up to you as it's likely those details will be unique to your use case or the application you're building.
Also, we encourage you to play around with the comment data. Try adding more parent and children comments to the data and see how it renders on the page.
You should now have a good understanding of recursion and how it can be used in a React application by building the skeleton of a comments section.