Recursive components in React: A real-world example
Tags: react, webdev
Published: 2022-11-15 17:11:07

**Written by [Rishi Purwar](https://blog.logrocket.com/author/rishipurwar/)✏️**

Have you ever used recursive components in [React](https://blog.logrocket.com/tag/react/)? I have. My first experience with them gave me an entirely new perspective on working on frontend projects. So, I thought it would be a good idea to write an article about a real-world example using recursive components in React to help folks become more familiar with working with them. 

In this article, we will explore the details of recursive components in React and their usage in a real-world application. We will look at an example of a recursive and non-recursive component in React and evaluate their modularity, readability, and maintainability. After that, we’ll build a real-world recursive component, a nested file explorer similar to VS Code. 

_Jump ahead:_

*   [What are recursive components in React?](#what-recursion-react)
*   [How is recursion different from loops in React?](#recursive-components-react-different-loops)
*   [Why and when to use recursive components in React](#why-when-use-recursive-components-react)
*   [Building a nested file explorer using standard React components](#build-nested-file-explorer-using-standard-react-components)
*   [Using recursive components in React to build a nested file explorer](#using-recursive-components-react-build-nested-file-explorer)

## What are recursive components in React? <a name="what-recursion-react">

Recursion is calling a function repeatedly within itself until a base condition is met (base case). Each time the recursive function calls itself, it takes a new argument. For example, the `factorial` function below works by repeatedly calling itself with a different argument until a base condition is met:

```javascript
function factorial(num) {
    if (num <= 1) { // base condition
        return 1;
    }
    return num * factorial(num - 1); // function calling itself with new input value.
}
console.log(factorial(6)); // 720 
```

Now that we’ve laid down the foundation for understanding recursive components, let’s look at them in React. As you may know, React components are functions. When a React component repeatedly renders inside itself with different props until a base condition is met, it’s called a recursive component. 

A recursive component is unique because it can call itself and helps render deeply nested data. These components are not limited to simply rendering parent data on the UI; they also render the parents’ [children’s data](https://blog.logrocket.com/deep-dive-iterating-context-children-react/) until the depth limit is reached. In these components, children can be set by [passing props](https://blog.logrocket.com/the-beginners-guide-to-mastering-react-props-3f6f01fd7099/). 

Let’s look at a simple example of a recursive component in React:

```javascript
import React from "react";

const RecursiveComponent = ({children}) => {
  return (
    <div>
      {children.length > 0 && <RecursiveComponent children={children} />}
    </div>
  );
};

export default RecursiveComponent;
```

If you’re curious about the real-world applications of this concept, you can see them in action as nested comment systems in [Reddit](https://www.reddit.com/) and file explorers similar to [VS Code](https://code.visualstudio.com/). 

Now that you have a fundamental understanding of recursive components, we’ll explore their uses and build a real-world example.

## How is recursion different from loops in React? <a name="recursive-components-react-different-loops">

You may be wondering about the critical differences between loops and recursion. In this section, we’ll take a look at those differences. In contrast to loops, recursion includes calling a function that calls itself, whereas loops require continuously calling the same code until a specific condition is met. 

With loops, we must first define our control variable before we can use it in any of the iterations of the loop. For instance, when we create `for loop` to loop through an array, we have to declare a counter variable, `let i=0`, to keep track of the number of iterations. This allows us to use the counter variable when we loop through our array. Otherwise, we won’t be able to use it when we need to, and we’ll need to `increment` or `decrement` these control variables to avoid infinite loops. 

On the other hand, we do not have to declare any variables to carry out recursive operations when using recursion. This is because recursive operations do not depend on variables and only need a base condition to stop calling a function.

*   Returnability: With loops, we cannot return anything. However, when we use recursion, we can return a value from a function
*   Readability and modularity: The code becomes more readable and modular with recursion. However, using loops makes code longer

## Why and when to use recursive components in React <a name="why-when-use-recursive-components-react">

In React, components are the primary building blocks for building user interfaces. They are awesome because they help us think about our app holistically and build it from smaller code chunks that are easier to reason. 

You may think, “why would we ever want to make recursive components?” The main reasons for using recursive components in React are that they make code [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself), more readable, and modular. 

With that out of the way, let’s focus on understanding when to use recursive components in React. The most common situation is when we have data nested several levels deep. 

Suppose we have an array of objects, and each object has a `children`​ key corresponding to another array of objects. Each object part of that array has a `children` key corresponding to another array of objects. Likewise, these objects can similarly contain more children's arrays. 

An example of such data looks like this:

```javascript
export const data = [
  {
    isFolder: true,
    name: "public",
    children: [
      {
        isFolder: false,
        name: "index.html",
      },
    ],
  },
  {
    isFolder: true,
    name: "src",
    children: [
      {
        isFolder: true,
        name: "components",
        children: [
          {
            isFolder: true,
            name: "home",
            children: [
              {
                isFolder: false,
                name: "Home.js",
              },
            ],
          },
        ],
      },
      {
        isFolder: false,
        name: "App.js",
      },
    ],
  },
];
```

As you can see, the above data has lots of nested children’s arrays. These nested items can go deeper, but I kept it to only four levels deep to explain things clearly. 

Using loops in this situation isn’t a good choice because it requires writing a lot of nested loops to loop through each level of data. This makes your code larger and harder to read. In addition, if we are unsure of how deep our data goes, it’s challenging to loop through all the nested data using a loop. So, in this case, it’s better to use recursion.

## Building a nested file explorer using standard React components <a name="build-nested-file-explorer-using-standard-react-components">

In this section, we will build a nested file explorer app using standard React components. In the next section of this tutorial, we will build the same React app by using recursive components. 

First, create a new React app and a `data` folder in the `src` folder. Then, create `data.js` inside the `data` and copy and paste the data from the "[Why and when to use recursive components in React](#why-when-use-recursive-components-react)" section into the later. 

Now, replace the code of your `App.js` file with the code below:

```javascript
import React from "react";
import { data } from "./data/data";

const NonRecursiveComponent = ({ data }) => {
  return <div>Non Recursive Component</div>;
};

const App = () => {
  return (
    <div style={{ margin: "8px" }}>
      <NonRecursiveComponent data={data} />
    </div>
  );
};
export default App;
```

We created a `NonRecursiveComponent` in the above code and [rendered it](https://blog.logrocket.com/react-conditional-rendering-9-methods/) inside the `App` component. Then, we passed the `data` prop from the `App` to the `NonRecursiveComponent`. 

Now, let’s start working on rendering the data on the UI. In the `NonRecursiveComponent`, replace the existing code with the following:

```javascript
const NonRecursiveComponent = ({ data }) => {
  return (
    <div>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
          </div>
        );
      })}
    </div>
  );
};
```

The above code will render all the `parent` (first level) data and display this on the UI: ![Rendered Recursive Component in React ](https://blog.logrocket.com/wp-content/uploads/2022/10/recursive-component-react-rendered.png) 

Now, let’s render the `children` by using the `map` method inside the second `return` statement. Your code should look like this:

```javascript
const NonRecursiveComponent = ({ data }) => {
  return (
    <div>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
            {parent.children.map((child) => { // rendering children of the parent
              return (
                <div key={child.name} style={{ paddingLeft: "20px" }}>
                  <span>{child.name}</span>
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
};
```

From there, you should see all the `children` of the `parent` on the UI: ![Children in React Recursive Component UI](https://blog.logrocket.com/wp-content/uploads/2022/10/react-recursive-coponent-children-ui.png) 

Let’s render the `grandchildren`. So, to do that, we need to do the same thing we did for `children`. Your code should look something like this:

```javascript
const NonRecursiveComponent = ({ data }) => {
  return (
    <div>
      {data.map((parent) => { // rendering parent data
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
            {parent.children.map((child) => { // rendering children of the parent
              return (
                <div key={child.name} style={{ paddingLeft: "20px" }}>
                  <span>{child.name}</span>
                  {child.children && // rendering grandchildren of the parent
                    child.children.map((grandChild) => {
                      return ( 
                        <div key={grandChild.name} style={{ paddingLeft: "20px" }}>
                          <span>{grandChild.name}</span>
                        </div>
                      );
                    })}
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
};
```

You should see something like this on the UI: ![Grandchildren in the Recursive Components in React](https://blog.logrocket.com/wp-content/uploads/2022/10/recursive-component-react-grandchildren.png) Now, the last thing we need to do is render `great-grandchildren` on the UI. We need to do the same thing we did for rendering `children` and `grandchildren`. After doing this, your code should look like this:

```javascript
const NonRecursiveComponent = ({ data }) => {
  return (
    <div>
      {data.map((parent) => { // rendering parent data
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
            {parent.children.map((child) => { // rendering children of the parent
              return (
                <div key={child.name} style={{ paddingLeft: "20px" }}>
                  <span>{child.name}</span>
                  {child.children && // rendering grandchildren of the parent
                    child.children.map((grandChild) => {
                      return (
                        <div
                          key={grandChild.name}
                          style={{ paddingLeft: "20px" }}
                        >
                          <span>{grandChild.name}</span>
                          {grandChild.children && // rendering great-grandchildren
                            grandChild.children.map((greatGrandChild) => {
                              return (
                                <div
                                  key={greatGrandChild.name}
                                  style={{ paddingLeft: "20px" }}
                                >
                                  <span>{greatGrandChild.name}</span>
                                </div>
                              );
                            })}
                        </div>
                      );
                    })}
                </div>
              );
            })}
          </div>
        );
      })}
    </div>
  );
};
```

Your UI should look like this: ![React Recursive Components File](https://blog.logrocket.com/wp-content/uploads/2022/10/react-recursive-components-file.png) 

So far, we’ve built a basic nested file explorer component using regular React components. However, as you can see, the `NonRecursiveComponent` code appears to be repeating itself for each nested level of data. As the nesting level of our data goes up, this code gets longer, making it more difficult to understand and maintain. 

So, how do we solve this problem? In the next section, we’ll look at how recursive components in React can help.

## Using recursive components in React to build a nested file explorer <a name="using-recursive-components-react-build-nested-file-explorer">

In this section, we’ll build the same nested file explorer using recursive components and implement a `show/hide` functionality for the nested files and folders. 

Let’s start by creating a new `RecursiveComponent` in the `App.js` file. Then, swap out the `NonRecursiveComponent` rendered in the `App` with the `RecursiveComponent`. Your code should look like this:

```javascript
const RecursiveComponent = ({ data }) => {
  return (
    <div style={{ paddingLeft: "20px" }}>
      Recursive Component
    </div>
  );
};

const App = () => {
  return (
    <div style={{ margin: "8px" }}>
      <RecursiveComponent data={data} />
    </div>
  );
};
```

Now, let’s render all the `parent` data on the UI:

```javascript
const RecursiveComponent = ({ data }) => {
  return (
    <div style={{ paddingLeft: "20px" }}>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
          </div>
        );
      })}
    </div>
  );
};
```

Next, let’s use recursion to render all the nested files and folder data. To do that, we need to do two things: first, render the `RecursiveComponent` from inside itself with a different `data` prop. Second, we need a base condition to stop rendering the `RecursiveComponent`. 

In our case, the base condition will be when the length of the `children` is zero or when they don’t exist, at which point we won’t call the `RecursiveComponent`. 

Your code should look like this:

```javascript
const RecursiveComponent = ({ data }) => {
  return (
    <div style={{ paddingLeft: "20px" }}>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            <span>{parent.name}</span>
            {/* Base Condition and Rendering recursive component from inside itself */}
            <div>
              {parent.children && <RecursiveComponent data={parent.children} />}
            </div>
          </div>
        );
      })}
    </div>
  );
};
```

Your UI should look like this: ![Real-World Example of React Recursive Components](https://blog.logrocket.com/wp-content/uploads/2022/10/recursion-react-components-output.png) 

😮 Surprise! With a few lines of code, we achieved the same output. This is the magic of recursion in React. 

Now, let’s implement `show/hide` to the nested files and folders. We need to make some changes to our code before we can start doing that. First, we need to use the `button` tag for the folder’s name and the `span` tag for the file’s name conditionally using the `isFolder` key in our data. We’ll do this because we’ll only add the `onClick` event to the folders and not to the files to show or hide all the files and folders inside a particular folder. 

Your updated code should look like this:

```javascript
const RecursiveComponent = ({ data }) => {
  return (
    <div style={{ paddingLeft: "20px" }}>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            {/* rendering folders */}
            {parent.isFolder && <button>{parent.name}</button>}
            {/* rendering files */}
            {!parent.isFolder && <span>{parent.name}</span>}
            <div>
              {parent.children && <RecursiveComponent data={parent.children} />}
            </div>
          </div>
        );
      })}
    </div>
  );
};
```

Now, let’s implement `show/hide` by creating a state using the [`useState` Hook](https://blog.logrocket.com/react-hooks-cheat-sheet-unlock-solutions-to-common-problems-af4caf699e70/) inside the `RecursiveComponent` like this:

```javascript
import { useState } from "react";

const RecursiveComponent = ({ data }) => {
  const [showNested, setShowNested] = useState({});
  // ...
  // rest of the code
  // ...
};
```

This `showNested` state variable will store all the opened folders like this:

```javascript
{
  public: true, // if the folder is opened, set it equal to true
  src: false // if the folder is not opened, set it equal to false
}
```

Now, create a function to handle `show/hide`:

```javascript
const RecursiveComponent = ({ data }) => {
  const [showNested, setShowNested] = useState({});

  // handle show/hide functionality
  const toggleNested = (name) => {
    setShowNested({ ...showNested, [name]: !showNested[name] });
  };
  // ...
  // rest of the code
  // ...
};
```

The `toggleNested` function accepts the folder’s name as an argument and then updates the value of that folder in `showNested` using the `setShowNested` function. This changes it from `false` to `true` or vice versa. 

Now, let’s add an `onClick` event to the `button` to invoke `toggleNested`. Then, pass the name of the folder as an argument when a user clicks any of the **folders**, as shown below:

```javascript
const RecursiveComponent = ({ data }) => {
  // ...
  // Rest of the code
  return (
    <div style={{ paddingLeft: "20px" }}>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            {parent.isFolder && (
              <button onClick={() => toggleNested(parent.name)}>
                {parent.name}
              </button>
            )}
            // ...
            // Rest of the code
            // ...
          </div>
        );
      })}
    </div>
  );
};
```

The final step is to update the `display` [CSS property](https://blog.logrocket.com/tag/css/) that we’ll add to the `div` wrapping the `RecursiveComponent` that’s inside the `RecursiveComponent`. When a user selects the **folder**, we’ll update the `showNested` object by adding the folder name as a `key` to that object. We’ll also set its value to `true` and add a check to see if the folder name is present in `showNested`. 

Then, we’ll set the `display` to `block`. Otherwise, we’ll set it to `none` to hide the nested files and folders:

```javascript
const RecursiveComponent = ({ data }) => {
  // ...
  // Rest of the code
  return (
    <div style={{ paddingLeft: "20px" }}>
      {data.map((parent) => {
        return (
          <div key={parent.name}>
            // ...
            // Rest of the code
            // ...

            // Updating the display property using the showNested state
            <div style={{ display: !showNested[parent.name] && "none" }}>
              {parent.children && <RecursiveComponent data={parent.children} />}
            </div>
          </div>
        );
      })}
    </div>
  );
};
```

Hopefully, you should be able to toggle through all the directories. And with that, this blog is finished!

## Conclusion

In this article, you’ve learned about recursive components in React, how to build them, and why we might use them. In addition, I showed how recursion is different from loops with a real-world example. Hopefully, you learned something new that will be useful for your next React project. 

I hope you enjoyed this article, and thanks for taking the time to read it. If you have any issues while following the article or have further questions, let me know in the comments section. If you like what I’m doing here and want to help me keep doing it, don’t forget to hit that share button.

---

##Cut through the noise of traditional React error reporting with LogRocket

[LogRocket](https://lp.logrocket.com/blg/react-signup-issue-free) is a React analytics solution that shields you from the hundreds of false-positive errors alerts to just a few truly important items. LogRocket tells you the most impactful bugs and UX issues actually impacting users in your React applications.

[![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://lp.logrocket.com/blg/signup)

[LogRocket](https://lp.logrocket.com/blg/react-signup-issue-free) automatically aggregates client side errors, React error boundaries, Redux state, slow component load times, JS exceptions, frontend performance metrics, and user interactions. Then LogRocket uses machine learning to notify you of the most impactful problems affecting the most users and provides the context you need to fix it.

Focus on the React bugs that matter — [try LogRocket today](https://lp.logrocket.com/blg/react-signup-issue-free).