Recursive elements in React
Tags: javascript, typescript, react, tutorial
Published: 2024-03-04 10:36:51


## Introduction

A couple of days back I was wondering how components like these are built:

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srpavevu4wxm6xdqph8p.gif" alt="intro-simple-tree.gif" />
  <figcaption>Tree Component</figcaption>
</figure>
</p>

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i62zwj7r256uef3wb5so.png" alt="intro-draw-component.png" />
  <figcaption>JSON to HTML Elements</figcaption>
</figure>
</p>

A common thing between these components is that there is a definitive pattern that gets repeated. For example, when you click on a title in the tree component, it expands. When you click on the inner title it expands and so on.

In the world of programming, to deal with these kinds of repetitive patterns we either use loops or recursions.

Everyone deals with them differently depending on their usecase. For this blogpost, I will use recursion to implement these components.

## Prerequisites

I would highly recommend going through the below topics before reading this blog post:

- *[Basics of Javascript](https://developer.mozilla.org/en-US/docs/Learn/JavaScript)*
- *[Basics of React](https://react.dev/)*
- *[styled-components](https://styled-components.com/docs/basics)*
- *[CSS pseudo-elements](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-elements)*

## What is Recursion?

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m89rrurwpz1if9t6blgy.gif" alt="what-is-recursion-i-know-a-guy.gif" />
  <figcaption>Saul's Magic</figcaption>
</figure>
</p>

As Sual Goodmen said, ‘Let’s just say I know a guy, who knows a guy, who knows another guy’. Recursion is similar to what he is trying to say.

From [Wikipedia](https://en.wikipedia.org/wiki/Recursion_(computer_science)),

<aside>
💡 ***Recursion** is a method of solving a [computational problem](https://en.wikipedia.org/wiki/Computational_problem) where the solution depends on solutions to smaller instances of the same problem.*

</aside>

In laymen terms, a problem is divided into a subproblem and the solution of that is passed down to the next subproblem. This goes on till the base condition is met where base condition stops this drill down.

Let us consider a classic example of finding a factorial of a number:

{% embed https://gist.github.com/keyurparalkar/eeca4981dfb218c5bc71609ad8de64a8 %}

So, in this function, `n` is just the number we're finding the factorial for. The function keeps calling itself with `n - 1` until it hits `0`. When it does, it just returns `1`. This is what we call the base case of the recursion. The return value gets multiplied with the current `n` and is sent back up to the previous stack frame (which is the last time we called the function with `n+1`). This cycle keeps on going until we get back to the very first function call (the original `n`), and bam! We get our final factorial.

## Why is Recursion?

There are a couple of advantages to using recursion that I have in mind:

- Simplicity and Readability
- Reduced Redundancy
- Divide and Conquer

You can read more about the advantages in this blog post: *[Recursion](https://pages.cs.wisc.edu/~vernon/cs367/notes/6.RECURSION.html#iter)*

## Let's talk about Recursive React Elements

From the definition of recursion explained above we know that a recursive function needs a base condition that helps it to get out of the recursion state. Similar to this function, we will make use of this concept in react to create recursive elements.

Here is a visual example of a recursive element:

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srpavevu4wxm6xdqph8p.gif" alt="intro-simple-tree.gif" />
  <figcaption>Tree Component</figcaption>
</figure>
</p>

This recursive tree is a component based on an object that has repetitive nested children. For example, the above tree component is based on the following JSON structure:

{% embed https://gist.github.com/keyurparalkar/3aa7a8b6bf746bff03568e99596a0876 %}

The component that you see above is a tree component. Let us recognize some key parameters in this component from the definition of recursion:

- **Recursive state**: Here the recursive state is the name or fields that are getting repeated one key within another.
    
    As you can see this object has an `id` `name` and `children` properties. Again the children's property is an array of tree i.e. object with `id` `name` and `children` properties. And this goes on and on. 
    
- **Base condition:** In this example, the base/end case is when there are no elements to print out.

We will be building an interactive component that will help us to visualize this object in the form of a tree. So without further ado! let us get started.

## Building the recursive element

What we are trying to implement is a tree that is interactive like we saw in the above section:

- We build this component out of the following tags:
    - `ul` - to wrap all the list children
    - `li` - to present each element in the list of children
    - `details` - to make each `li` tag interactive. This will help it to open and close the `li` tag.
    - `summary` - This will help to give the heading to the `li` tag.
- So the structure is like this: `ul` wraps all `li` and each `li` has `details` and `summary`.

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hpv7myou8nru56byrvuf.jpeg" alt="Representation of Tree with the above elements" />
  <figcaption>Representation of Tree with the above elements</figcaption>
</figure>
</p>

Let us call this component a `RecursiveTree` and create the component file for the same. Paste the below code in it:

{% embed https://gist.github.com/keyurparalkar/176a59c555022cc8b532dd325a34262c %}

Let me explain what’s going on here:

- We have a styled component: `StyledUnorderedList` that has the following styles:
    
{% embed https://gist.github.com/keyurparalkar/cde8163712162a8c20c04a231f69c0b3 %}
    
- We loop over all the children's elements with the map function that wraps each item with the `CustomDetails` component:
    
{% embed https://gist.github.com/keyurparalkar/7f3d5cd8141a2395b44e4dc22a18ab2b %}
    
- This `CustomDetails` component looks like below:

{% embed https://gist.github.com/keyurparalkar/3c33b27c6ad2f0403226201145e3001c %}
    
    
- The purpose of this component is to provide modified/additional functionalities apart from the existing `details` HTML element. Here are the additional functionalities that it provides:
    - You can provide icons that can be rendered in front of each element in the tree.
        - For that, you need to provide an array of two icons. The first one is the open icon and the second is the close icon.
        - It is to be noted that I made use of *[react-icons](https://react-icons.github.io/react-icons/)* icon library.
    - Interactive change of icon when the detail’s tag gets toggled.
- The component above is pretty self-explanatory and you can get a jest of out of it by a glance.
- Let us test out this component. Render this component as below and see the output:
    
{% embed https://gist.github.com/keyurparalkar/d841a51525b5c10825f76d467e73351f %}

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eo0ybwah9hinl2qb49n3.gif" alt="Tree with no custom icon field in the JSON object" />
  <figcaption>Tree with no custom icon field in the JSON object</figcaption>
</figure>
</p>
    
- You can also pass your desired icons in the tree config like below:

{% embed https://gist.github.com/keyurparalkar/114cc84b4ffb3989626cb28ba951ca15 %}

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6c3lleww85ycjarysmo.gif" alt="Tree with custom icon field in the JSON object" />
  <figcaption>Tree with custom icon field in the JSON object</figcaption>
</figure>
</p>

## Caveat: Event bubbling

One thing I struggled with during the implementation of this component was the toggle interaction that happened at deeper levels of the tree where getting bubble i.e. the toggle event was getting applied from the target element to all the parent elements that had event handlers that catch this toggle event.

To avoid this scenario, I made use of the `e.stopPropogation` function to stop the event from ***[bubbling](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling).***

To better explain the problem here are the visualized representations of the same:

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x6c3lleww85ycjarysmo.gif" alt="No event bubbling" />
  <figcaption>No event bubbling</figcaption>
</figure>
</p>

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yme2ak7260vft3z8hwlo.gif" alt="With Event bubbling" />
  <figcaption>With Event bubbling</figcaption>
</figure>
</p>

It took me a small bit of time to understand the issue at hand but after careful debugging, I was able to resolve it. 

So to provide a better interactivity in the recursive elements make sure that the events don’t get bubbled up (if that’s the desired behaviour you want). 

## Bonus Element!!

So this was fun. So before closing up, I would also like to share another example. This example is of recursively adding components based on a JSON config. I will just place the code below along with its output for reference.

{% embed https://gist.github.com/keyurparalkar/6824590ee3edfafc33f22e3247cc19a8 %}

You get the following out: 

<p>
<figure>
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i62zwj7r256uef3wb5so.png" alt="intro-draw-component.png" />
  <figcaption>JSON to HTML Elements</figcaption>
</figure>
</p>

## Summary

To summarize, we learned a couple of things here:

- What is recursion?
- What are recursive react elements?
- Building the RecursiveTree component
- Caveats
- Bonus Element

The entire code for this tutorial can be found [here](https://github.com/keyurparalkar/recursive-component-examples).

Thank you for reading!

Follow me on [twitter](https://twitter.com/keurplkar), [github](http://github.com/keyurparalkar), and [linkedIn](https://www.linkedin.com/in/keyur-paralkar-494415107/).