AN.
  • Home
  • Experience
  • Projects
  • Blog
AN.

Built with Next.js, Tailwind v4, and Framer Motion.

GitHubLinkedInNPM
© 2026 Ahmed Nasser. All rights reserved.
Back to writing
February 10, 2024•
3 min read

How To Make Recursion: Use Case For new Map Syntax

#React#JavaScript#Recursion#Map#State Management#Web Development
A
Ahmed NasserSenior Software Engineer

In this article, I'll demonstrate how to implement recursion in a React component to manage radio button groups. Additionally, we'll explore a use case for the new Map syntax in JavaScript.

Managing deeply nested UI structures—like file trees, nested comments, or multi-level category selectors—can be challenging in React. Recursion is a powerful technique that allows a component to call itself, making it perfect for these scenarios.

In this guide, we'll build a recursive radio button selector and explore why JavaScript's Map object is the ideal choice for managing its state.


Why Use the Map Object?

While plain objects are common, the Map object offers several advantages for dynamic state management:

  • Order Preservation: Maps remember the original insertion order of keys.
  • Any Key Type: Unlike objects (which only allow strings or symbols), Maps can use numbers, objects, or even other components as keys.
  • Size Property: You can get the number of items instantly with map.size.
  • Performance: Maps are often more efficient for frequent additions and removals.

1. Initializing State with Map

We'll use a Map where the key is the nesting level (depth) and the value is the ID of the selected item at that depth.

const [choicesState, setChoicesState] = useState(new Map<number, number>());

2. Managing Selections Recursively

When a user selects an item at a certain level, we need to:

  1. Update the selection for that level.
  2. Clear all selections at deeper levels (since the path has changed).
const handleChoices = (level: number, id: number) => {
  // 1. Create a fresh Map to maintain immutability
  const newChoicesState = new Map(choicesState);
 
  // 2. Set the current level selection
  newChoicesState.set(level, id);
 
  // 3. Cleanup: Remove any "stale" selections at deeper levels
  for (const [key] of newChoicesState) {
    if (key > level) {
      newChoicesState.delete(key);
    }
  }
 
  setChoicesState(newChoicesState);
};

3. The Recursive Component

The RadioGroup component renders a list of items. If an item is selected and it has children (sub-items), the component calls itself to render the next level.

interface Item {
  id: number;
  name: string;
  children?: Item[];
}
 
const RadioGroup = ({ data, level = 0, handleChoices, choicesState }) => {
  const selectedId = choicesState.get(level);
  const selectedItem = data.find(item => item.id === selectedId);
 
  return (
    <div className="flex flex-col gap-4 pl-4 border-l-2 border-zinc-100">
      {/* Render current level items */}
      <div className="space-y-2">
        {data.map((item) => (
          <label key={item.id} className="flex items-center gap-2 cursor-pointer">
            <input
              type="radio"
              name={`level-${level}`}
              checked={selectedId === item.id}
              onChange={() => handleChoices(level, item.id)}
              className="w-4 h-4 text-primary"
            />
            <span className="text-sm font-medium">{item.name}</span>
          </label>
        ))}
      </div>
 
      {/* RECURSION: Render children if an item is selected */}
      {selectedItem?.children && (
        <RadioGroup
          data={selectedItem.children}
          level={level + 1}
          handleChoices={handleChoices}
          choicesState={choicesState}
        />
      )}
    </div>
  );
};

When to Use This Pattern?

  1. File Explorers: Navigating folders and subfolders.
  2. Category Selectors: Choosing a category (e.g., Electronics > Computers > Laptops).
  3. Comment Threads: Rendering nested replies in a discussion forum.
  4. Org Charts: Visualizing company hierarchies.

Performance Tip: Memoization

Recursive components can re-render frequently. If your tree is large, wrap your component in React.memo and use useCallback for the handleChoices function to prevent unnecessary updates.

const MemoizedRadioGroup = React.memo(RadioGroup);

Conclusion

Recursion in React, combined with the power of JavaScript Map, provides a clean and scalable way to handle complex data structures. By clearing deeper levels on every change, you ensure your application state remains consistent and easy to reason about.

Share on TwitterShare on LinkedIn
A

Written by Ahmed Nasser

Senior Frontend Engineer

Passionate about building exceptional digital experiences. Specialized in React, Next.js, and modern web architectures. I love sharing my knowledge through technical writing and open-source contributions.

Social
TwitterLinkedInGitHub

Share

Share on TwitterShare on LinkedIn

Continue Reading

More articles you might find interesting

View all articles
Jan 15, 2024
5 min

Clean Your Objects Efficiently in JavaScript

Learn how to streamline your API data handling by efficiently removing null, undefined, and empty values from JavaScript objects using Lodash and recursion.

#JavaScript#React
Jan 4, 2026
3 min

Why Your React State is "One Step Behind" 🐢

Have you ever tried to log or send state immediately after calling its set function, only to find the old value instead? This is one of the most common "aha!" moments for React developers.

#React#JavaScript
Mar 5, 2024
5 min

Why You Should Not Use Index as Key in React Lists

Discover why using array indices as keys in React can lead to performance issues and bugs, and learn the best practices for proper list rendering.

#React#Next.js