Recursive rendering in React
Tags: react, algorithms, webdev, javascript
Published: 2022-11-18 19:08:46

In one of my very first tech interviews earlier this year, I was given an interesting problem and I terribly messed it up. Meaning I couldn’t solve it. And the solution to the problem was recursion but in react. So I decided to write a blog about it. 

### What is Recursion?

In computer science, recursion is **a method of solving a computational problem where the solution depends on solutions to more minor instances of the same problem**. Recursion solves such recursive problems by using functions that call themselves from within their own code. 

For example, a factorial(5) is 5*4*3*2*1. If we want to solve it recursively, we can say a factorial(5) is 5 times the factorial(4): 5*4! 

And factorial(4) is 4*3! until we reach the number 1.

```jsx
5!
	5 * 4!
		5 * 4 * 3!
			5 * 4 * 3 * 2!
				5 * 4 * 3 * 2 * 1
```

We eventually reach the same solution which is 5 * 4 * 3 * 2 * 1. If we have to write a function for factorial we can write the following: 

```jsx
function factorial(n){
   return n * factorial(n ‑ 1);
}
```

If we invoke the factorial() function and pass an integer n, it will keep calling the factorial() * n, and in each invocation, n will be n-1. 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/moimaklg0wxdy72fjamv.png)

However, we have a serious problem. We did not tell our function when to stop and therefore our factorial() function will end up in an infinite loop and we will never reach the solution. Telling the function when to terminate is called a *base case. Base case* is always required when defining a recursive function. The **base case** in this case would be n = 1. Since factorials of numbers that are less than 1 don't make any sense, we stop at the number 1 and return the factorial of 1 (which is 1). 

```jsx
function factorial(n){
	if(n === 1)
		return 1;
	else
		return n * factorial(n ‑ 1);
}
```

Now if we pass 5 as n: factorial(5)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j7isv9918ji0yqj8c0mz.png)

### How do we handle recursion in React?

What would a recursive call look like in react? Let’s say you are making an API call and the response data has children that is also the same key and value format. 

```json
{
  text: "some text",
  data: {
      text: "some text",
      data: {
        text: "some text",
        data: {
          text: "No more data here"
        }
    }
  }
}
```

As you can see the object `data` is continuously stacked on top of another `data` object. We can have indefinite amount of stacked data. Using recursion we will render the data. 

Say that our component is called `<RecursivelyRenderComponent>` which takes the `data` object as a prop and will render the `text` inside the `data` object.

```jsx
function RecursivelyRenderComponent({ data }) {
  return (
    <div>
      <h1>{data.text}</h1>
    </div>
  );
}
```

This will return the first instance of the text. But what about the nested ones? 

We need to recursively return the same component within *itself* for the amount of time we encounter `data`. 

Our recursion will look like:

- **Base case:** If `data` does’t exist we stop recursion
- **Recursion rule:** If `data` exist render `<RecursivelyRenderComponent>` again and pass `data` as a prop.

Our component will look like this: 

```jsx
function RecursivelyRenderComponent({ data }) {
  if (data.data)
    return (
      <div>
        <h1>{data.text}</h1>
        <RecursivelyRenderComponent
          data={data.data}
        ></RecursivelyRenderComponent> {/*calling the same component recursivly */}
      </div>
    );
  else return <h1>{data.text}</h1>;
}
```

We can simplify it more using ternary: 

```jsx
function RecursivelyRenderComponent({ data }) {
  return (
    <div>
      <h1>{data.text}</h1>
      {data.data ? (
        <RecursivelyRenderComponent
          data={data.data}
        ></RecursivelyRenderComponent> {/*calling the same component recursivly */}
      ) : null}
    </div>
  );
}
```

And our DOM will look like this: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtm7xktpy5sek6d94a5i.png)

### Let’s analyze a real-life scenario


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aodim3ggd5cfinqg5sko.png)

This is a thread from a random Reddit post. As seen in the picture a Reddit post can have multiple replies, and the replies can also have multiple replies. The replies to a post can be heavily nested. In this example, each new thread has a space and a line indicating the parent reply. Similar to our previous example of  `<RecursivelyRenderComponent/>`, this type of data could be handled using recursion. 

### How do we render reddit style replies?

Sample response data: 

```jsx
const data = [
  {
    post: {
      id: 1,
      author: "goodKitty",
      title: "A day in a life of a kitten!",
      text: "Claws in your leg the best thing in the universe is a cardboard box lie on your belly and purr when you are asleep so chase ball of string yet i like big cats and i can not lie wake up human for food at 4am. Ask for petting stand with legs in litter box, but poop outside yet climb leg, yet favor packaging over toy. Stare at wall turn and meow stare at wall some more meow again continue staring the dog smells bad miaow then turn around and show you my bum and cry louder at reflection yet missing until dinner time lasers are tiny mice.",
      reply: [
        {
          author: "KittyLord",
          text: "Love it!",
          reply: [
            {
              author: "Hungrycat22",
              text: "Meow To!",
              reply: [
                {
                  author: "catnipDealer",
                  text: "purrrrrrrr!!",
                  reply: [
                    {
                      author: "KittyLord",
                      text: "Purrfect!",
                    },
                  ],
                },
              ],
            },
            {
              author: "Hungrycat22",
              text: "Mice!!!",
            },
          ],
        },

        {
          author: "CatM0m",
          text: "I have a cat!",
          reply: [
            {
              author: "dirtyKitten",
              text: "I have 2 cats",
              reply: [
                {
                  author: "CatM0m",
                  text: "Hahahaha",
                },
              ],
            },
          ],
        },
      ],
    },
  },
]
```

This is similar data to a Reddit post. We have `post`s, which contains replies, and the replies contain more replies. The replies should be rendered under the post and should keep nesting under other replies until there are no replies in the data.  

```jsx
function Reply({ reply }) {
  return (
    <div>
        {reply.author} replied
      </p>
        {reply.text}
      </p>
      <div>
         {reply.reply
           ? reply.reply.map((reply) => <Reply reply={reply}></Reply>)
           : null}
      </div>
    </div>
  );
}
```

Our `<Reply/>` component takes a prop `reply`, it renders the author and text of the reply and check if the data has any `reply` inside. If there is a `reply` field, we map through it (since `reply` returns an array) and re-render the `<Reply/>` for each element of the array and pass the element as a prop: `reply.reply.map((reply) => <Reply reply={reply}></Reply>)`.

If there is no `reply` we stop the recursion and **that’s our base case.**

Adding some forum style spacing to it. 

```jsx
function Reply({ reply }) {
  return (
    <div>
      <p
        style={{
          marginLeft: "10px",
          textDecoration: "underline",
          color: "grey",
          fontStyle: "italic",
        }}
      > 
        {reply.author} replied
      </p>
      <p
        style={{
          marginLeft: "10px",
                  backgroundColor: "beige",
          padding: '20px'
        }}
      >
        {reply.text}
      </p>
      <div className="forum">
        <div className="break"></div>
        <div>
          {reply.reply
            ? reply.reply.map((reply) => <Reply reply={reply}></Reply>)
            : null}
        </div>
      </div>
    </div>
  );
}
```

Css: 

```css
.forum{
  display: flex;
  flex-direction: row;
}

.break{  /* this is the line */           
  margin-left: 40px;
  background-color: cadetblue;
  width: 2px;
}
```

Let’s also render the `post` data in our `<App/>` component and render the replies. 

```css
function App() {
  return (
    <div className="App">
      <h1>{data[0].post.title}</h1>
      <p>By: {data[0].post.author}</p>
      <p>{data[0].post.text}</p>

      {data[0].post.reply
        ? data[0].post.reply.map((reply) => <Reply reply={reply}></Reply>)
        : null} {/* we are mapping through the direct replies to the post */}
    </div>
  );
}
```

And finally our DOM will look like: 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87brtwfm7c0od6ffyov5.png)

It’s as simple as that. This will work for indefinite amount of nested data without a problem.