## Recursive React Components

It can be easy to forget that React components are *just* functions. They receive inputs, they give us an output, and they might trigger some side effects in the process. Because they are simply functions, we can use patterns with them that we use with other functions. Like **recursion**.

### What is recursion?

Recursion is the pattern of a function calling itself. A very common example of a recursive function is calculating a *factorial* of a number. Consider the following function:

```
function factorial(number) {
// This is the base case. I'll explain this shortly
if (number <= 1) {
return 1
}
return number * factorial(number - 1)
}
```

Our function receives a number to factorialize, but rather than use an iterative loop, such as a `for`

or `while`

loop, we take advantage of the fact that we can calculate the final result by utilizing the results of calling `factorial`

on smaller numbers. That is, we recognize the pattern:

```
factorial(4) === 4 * factorial(3)
factorial(3) === 3 * factorial(2)
factorial(2) === 2 * factorial(1)
factorial(1) === 1
```

If we take this list of equal values and reverse the order of the functions we see called, we can derive the function call stack of `factorial(4)`

.

`factorial(4)`

leads to `factorial(3)`

getting called, which leads to `factorial(2)`

getting called, which leads to `factorial(1)`

getting called, which returns the value of `1`

, which is fed back into `factorial(2)`

which returns the value of `2`

, which is fed back into `factorial(3)`

which returns the value of `6`

, which is fed back into `factorial(4)`

, which returns the value of `24`

.

Easy, right?!

### Base Cases

Consider for a moment if we commented out the following bit of code from our `factorial`

function:

```
function factorial(number) {
// if (number <= 1) {
// return 1
// }
return number * factorial(number - 1)
}
```

What would happen? Well, we'd never get an answer. We'd never get a call to `factorial`

that returned a value. We would continue to add `factorial`

calls to the call stack until we exceeded the maximum number of calls allowed on the stack. We would have a "stack overflow" (and yes, that is where the name comes from).

Every recursive function needs to have a **base case** that ends the recursion. In the case of `factorial`

, it's when we have a number less than or equal to 1 passed in for `number`

. This base case ends the chain of recursive calls, and starts the process of returning values up the stack to get the final result.

### Recursion applied to components

Now that we understand recursive functions, let's apply this knowledge to components. A recursive component is a component that renders itself as one of its children. Let me give you an example.

Consider a directory of folders. It might look something like this:

```
src
|- css
|- js
|- utils
|- components
public
|- images
```

How can we represent this as data to pass to a recursive component? Pretty simply actually, we can use a **tree**. A tree is a graph data structure where each child node has a single parent. For example, the HTML structure of a website is a tree. No element on a page has more than one parent (all they way up to the `<html>`

tag). We can make a tree structure for our `folders`

like this:

```
const folders = [
{ name: 'src', children: [
{ name: 'css', children: [] }
{ name: 'js', children: [
{ name: 'utils', children: [] },
{ name: 'components', children: [] }
]}
]},
{ name: 'public', children: [
{ name: 'images', children: [] }
]}
]
```

We have a top level of folders, and folders nested up those are on a `children`

property. Now that we have our data, how do we make use of it in a recursive component?

Similar to how we recognized that `factorial`

can be solved by using the result of `factorial`

called on smaller numbers, we can recognize that a tree is the result of combining smaller trees. Understanding this, we can make a `Tree`

component that will call itself to render smaller `Tree`

s.

```
function Tree({ items }) {
// our base case, if we have no items, render nothing.
if (!items || !items.length) {
return null
}
return items.map(item => (
<React.Fragment key={item.name}>
<div>{item.name}</div>
{/* And here's the recursion! */}
<Tree items={item.children} />
</React.Fragment>
))
}
```

If we were to pass the folder data we created earlier to the component, that will look like this:

**Wait!** That's not what we want to represent. That's just a flat list. What happened?

Well, we forgot to style it. Let's track the `depth`

of the folder with each level and update the `padding-left`

CSS property accordingly.

```
// We add a `depth` property with a default value of 0
// That way we don't have to pass it to the top level of the tree
function Tree({ items, depth = 0 }) {
if (!items || !items.length) {
return null
}
return items.map(item => (
<React.Fragment key={item.name}>
{/* Multiply the depth by a constant to create consistent spacing */}
<div style={{ paddingLeft: depth * 15 }}>{item.name}</div>
<Tree items={item.children} depth={depth + 1} />
</React.Fragment>
))
}
```

Notice how simple it is to increment the `depth`

prop with recursion. Each layer deeper we go in the tree, the value is increased by 1. Let's take a look at our recursive component now:

That looks a bit more like the folder structure we all know and love. Let's add a few more touches to make it a bit nicer.

That's starting to look like something you could use in a real UI. A little interactivity, displaying of files, and we'd really have something.

### Conclusion

I encourage you to get comfortable with recursion. It doesn't have to be scary. Often, it's the simplest and most elegant solution to a problem. Who knows, it might even help you pass a job interview one day. Don't be afraid to experiment with it in your React work, you may discover some interesting UIs because of it.

### Finished reading?

Here are a few options for what to do next.

### Let's talk some more about JavaScript, React, and software engineering.

I write a newsletter to share my thoughts and the projects I'm working on. I would love for you to join the conversation. You can unsubscribe at any time.