Architecture
React Apple Tree is built with a clean separation of concerns, featuring two main component exports that handle different use cases.
Component Variants
ReactAppleTree
The default export that includes a React DnD context provider.
import React from 'react' ;
import { DndProvider } from 'react-dnd' ;
import { HTML5Backend } from 'react-dnd-html5-backend' ;
import ReactAppleTreeWithoutDndContext from './ReactAppleTreeWithoutDndContext' ;
import { ReactAppleTreeProps } from './types' ;
export default function ReactAppleTree < T >(
props : React . PropsWithChildren < ReactAppleTreeProps < T >>,
) {
return (
< DndProvider backend = { HTML5Backend } >
< ReactAppleTreeWithoutDndContext { ... props } />
</ DndProvider >
);
}
When to use: This is the recommended variant for most use cases. Use this when you don’t have an existing React DnD context in your application.
ReactAppleTreeWithoutDndContext
A variant without the DnD context wrapper for advanced use cases.
src/ReactAppleTreeWithoutDndContext.tsx
export default function ReactAppleTreeWithoutDndContext < T >(
props : React . PropsWithChildren < ReactAppleTreeProps < T >>,
) {
return (
< PropDataContextProvider >
< TreeDataContextProvider >
< SearchContextProvider >
< DNDContextProvider >
< StyledReactAppleTree className = { props . className } >
< TreeList { ... props } />
</ StyledReactAppleTree >
</ DNDContextProvider >
</ SearchContextProvider >
</ TreeDataContextProvider >
</ PropDataContextProvider >
);
}
When to use: Only use this variant if you already have a DndProvider in your application hierarchy. This prevents nested DnD contexts which can cause conflicts.
Context Hierarchy
The component uses a layered context architecture for state management:
PropDataContext
Stores and provides access to all props passed to the component. This allows child components to access configuration without prop drilling.
TreeDataContext
Manages the internal tree state:
treeMap : A flattened map of all nodes indexed by their keys
flatTree : A flat array representation of visible nodes for rendering
setTreeMap/setFlatTree : Functions to update the tree state
SearchContext
Handles search functionality:
Search query state
Search results and matching nodes
Focus management for search results
DNDContext
Manages drag-and-drop operations:
Dragging node information
Drop zone calculations
Drop validation logic
Data Flow
Component Hierarchy
Root Component
ReactAppleTree or ReactAppleTreeWithoutDndContext receives props and initializes contexts
TreeList
Renders the virtualized list of tree items. Manages the list layout and passes data to individual items.
TreeItem
Individual tree nodes with drag handles, drop targets, and expand/collapse controls. Each item has access to:
Node data and metadata
Drag and drop hooks
Expansion state
Custom renderers
Props Flow
All props passed to ReactAppleTree are stored in PropDataContext and accessed by child components:
interface ReactAppleTreeProps < T > {
// Required
treeData : Array < TreeItem < T >>; // The tree structure
onChange : ( treeData : Array < TreeItem < T >>) => void ; // Update handler
getNodeKey : GetNodeKeyFn < T >; // Node key extractor
// Optional callbacks
generateNodeProps ?: GenerateNodePropsFn < T >;
onMoveNode ?: OnMoveNodeFn < T >;
onVisibilityToggle ?: OnVisibilityToggleFn < T >;
onDragStateChanged ?: OnDragStateChangedFn < T >;
// Drag and drop configuration
canDrag ?: CanDragFn ;
canDrop ?: CanDropFn < T >;
dndType ?: string ;
shouldCopyOnOutsideDrop ?: boolean | (( data ) => boolean );
// Tree configuration
maxDepth ?: number ;
canNodeHaveChildren ?: boolean | (( node ) => boolean );
// Styling and rendering
scaffoldBlockPxWidth ?: number ;
rowHeight ?: number ;
nodeContentRenderer ?: NodeRenderer < T >;
placeholderRenderer ?: PlaceholderRenderer < T >;
// Search
searchQuery ?: string ;
searchMethod ?: SearchMethodFn < T >;
searchFocusOffset ?: number ;
// Performance
isVirtualized ?: boolean ;
}
State Management
Internal State
The component maintains two key internal representations:
TreeMap : Object mapping node keys to node data for O(1) lookups
FlatTree : Array of visible nodes in render order
State Updates
When tree data changes:
Flatten
Tree data is flattened into treeMap and flatTree representations
Render
flatTree is used for efficient rendering, only showing expanded nodes
Update
On user interactions, internal state is updated and onChange is called with the new tree
Virtualization By default, the tree uses virtualization (react-window) to only render visible nodes, enabling smooth performance with thousands of items.
Flat Structure Maintains a flattened representation of visible nodes for O(1) access during rendering and drag operations.
Context Separation Separates concerns into focused contexts to minimize unnecessary re-renders.
Lazy Updates Only expands/collapses nodes on demand, avoiding computation for hidden subtrees.
Usage Examples
Basic Usage (Recommended)
import ReactAppleTree from 'react-apple-tree' ;
import 'react-apple-tree/dist/index.css' ;
function MyTree () {
const [ treeData , setTreeData ] = useState ([
{
id: '1' ,
title: 'Parent Node' ,
expanded: true ,
children: [
{ id: '1-1' , title: 'Child Node' }
]
}
]);
return (
< ReactAppleTree
treeData = { treeData }
onChange = { setTreeData }
getNodeKey = { ({ node }) => node . id }
/>
);
}
With Existing DnD Context
import { DndProvider } from 'react-dnd' ;
import { HTML5Backend } from 'react-dnd-html5-backend' ;
import { ReactAppleTreeWithoutDndContext } from 'react-apple-tree' ;
function App () {
return (
< DndProvider backend = { HTML5Backend } >
{ /* Other components using DnD */ }
< MyTree />
</ DndProvider >
);
}
function MyTree () {
return (
< ReactAppleTreeWithoutDndContext
treeData = { treeData }
onChange = { setTreeData }
getNodeKey = { ({ node }) => node . id }
/>
);
}
Next Steps
Tree Data Structure Learn about the TreeItem interface and how to structure your data
Tree Operations Explore utility functions for manipulating tree data
Drag and Drop Understand how drag-and-drop functionality works
API Reference View complete API documentation