Hone logo
Hone
Problems

Implement a Recursive Tree View Component in React

Develop a reusable React component that can render hierarchical data structures (trees) in a visually organized manner. This component is essential for applications that display nested information, such as file explorers, organizational charts, or category navigations, providing a user-friendly way to explore complex data.

Problem Description

Your task is to create a TreeView component in React using TypeScript. This component should accept an array of TreeNode objects, where each node can have children, and recursively render the entire tree structure.

Key Requirements:

  • Recursive Rendering: The component must be able to render nodes at any depth of the tree.
  • Expand/Collapse Functionality: Each node should have a visual indicator (e.g., an arrow or plus/minus icon) that allows users to expand or collapse its children.
  • Indentation: Child nodes should be visually indented to reflect their hierarchical relationship with their parent.
  • Customizable Node Content: Allow for the rendering of custom content within each node.

Expected Behavior:

  • When the component mounts, all nodes should be initially collapsed (except possibly the root level).
  • Clicking an expand/collapse indicator should toggle the visibility of that node's children.
  • The component should handle empty nodes (nodes with no children) gracefully.

Edge Cases to Consider:

  • An empty input array.
  • Nodes with very deep nesting.
  • Nodes with empty or null children arrays.

Examples

Example 1:

Input Data (TypeScript Interface):

interface TreeNode {
  id: string;
  name: string;
  children?: TreeNode[];
}

const sampleData: TreeNode[] = [
  {
    id: '1',
    name: 'Root Node 1',
    children: [
      { id: '1-1', name: 'Child 1.1' },
      {
        id: '1-2',
        name: 'Child 1.2',
        children: [
          { id: '1-2-1', name: 'Grandchild 1.2.1' },
          { id: '1-2-2', name: 'Grandchild 1.2.2' },
        ],
      },
    ],
  },
  { id: '2', name: 'Root Node 2' },
];

Expected Output (Conceptual Render):

▶ Root Node 1
  ○ Child 1.1
  ▶ Child 1.2
    ○ Grandchild 1.2.1
    ○ Grandchild 1.2.2
▶ Root Node 2

(Note: '▶' indicates an expanded node, '○' indicates a collapsed or leaf node. The indentation is also crucial.)

Explanation:

The TreeView component receives sampleData. It renders 'Root Node 1' and 'Root Node 2' at the top level. 'Root Node 1' has children, so it displays an expand indicator. Its children ('Child 1.1' and 'Child 1.2') are indented. 'Child 1.2' also has children and is initially expanded, showing its indented grandchildren. 'Root Node 2' has no children and is rendered as a leaf node.

Example 2:

Input Data:

const emptyData: TreeNode[] = [];

Expected Output (Conceptual Render):

(Nothing is rendered, or an empty state message like "No data to display")

Explanation:

When provided with an empty array, the TreeView component should render nothing or an appropriate empty state message.

Example 3:

Input Data:

const complexData: TreeNode[] = [
  {
    id: 'a',
    name: 'Branch A',
    children: [
      { id: 'a-1', name: 'Leaf A.1' },
      { id: 'a-2', name: 'Leaf A.2', children: [] }, // Node with empty children array
    ],
  },
  {
    id: 'b',
    name: 'Branch B',
    children: null, // Node with null children
  },
];

Expected Output (Conceptual Render):

▶ Branch A
  ○ Leaf A.1
  ○ Leaf A.2
▶ Branch B

Explanation:

This example demonstrates handling nodes with explicit empty children arrays and nodes where children is null. Both should be treated as leaf nodes.

Constraints

  • The TreeNode interface will have at least id (string) and name (string). The children property will be an optional array of TreeNode.
  • The TreeView component should not rely on any external tree view libraries.
  • The solution should be implemented using functional components and React hooks.
  • Performance is important; the component should be reasonably efficient for trees with up to a few hundred nodes.

Notes

  • Consider using CSS for styling the indentation and expand/collapse indicators.
  • You might want to manage the expanded state of nodes internally or allow it to be controlled externally. For this challenge, internal state management is sufficient.
  • Think about how you will pass down the recursive structure of the component.
  • The id property should be used as the key prop for list rendering.
Loading editor...
typescript