How React compares old and new fiber trees to decide what to update, insert, or delete.
Reconciliation is React's algorithm for efficiently updating the UI when state or props change. Rather than re-rendering the entire DOM tree, React compares the previous virtual DOM tree with the newly rendered tree and computes the minimum number of operations needed. It uses two key heuristics to do this in O(n) time instead of O(nΒ³).
React assumes: (1) Elements of different types produce completely different trees β so React unmounts the old subtree and mounts a fresh one. (2) The developer can hint at stable identity across renders using the key prop.
When two elements have the same type (e.g., both <div>), React keeps the existing DOM node and only updates the changed attributes/props. This avoids destroying and recreating DOM nodes unnecessarily.
If the type changes (e.g., <div> becomes <span>), React unmounts the old component tree entirely (running all cleanups) and mounts the new tree fresh. State is lost.
For lists of children, React matches old and new items by key. Without keys, React uses position β which can cause unnecessary unmounts when items reorder. Keys let React efficiently move existing DOM nodes instead.
As React walks both trees, it builds an 'effect list' β a linked list of fibers that have work to do (updates, insertions, deletions). The commit phase walks this list and applies changes to the real DOM.
A unit of work in React's reconciliation engine. Each component has a fiber node storing type, props, state, and pointers to parent/child/sibling fibers.
A clone of the current fiber tree where React applies changes during reconciliation. Only promoted to 'current' after the commit phase completes.
A flat linked list of fibers with pending DOM mutations, built during reconciliation and walked during the commit phase.
When React detects that a fiber's props and context haven't changed, it can skip rendering that subtree entirely β a key performance optimization.
1// Without keys β position-based matching (bad for reordering)2// Old: [<A/>, <B/>, <C/>]3// New: [<B/>, <A/>, <C/>]4// React sees: position 0 changed (updates AβB), position 1 changed (updates BβA)5// Result: 2 updates + possible state loss67// With keys β identity-based matching (correct)8// Old: [<A key="a"/>, <B key="b"/>, <C key="c"/>]9// New: [<B key="b"/>, <A key="a"/>, <C key="c"/>]10// React sees: same keys, just reordered11// Result: 0 updates, 2 DOM moves β much more efficient
Reconciliation is what makes React's declarative model practical. You describe what the UI should look like, and React figures out the minimum set of DOM changes needed. The Fiber architecture makes this interruptible β React can pause reconciliation mid-tree and resume it later, enabling concurrent features like Suspense and transitions.
You have a todo list where users can delete items from the middle. Each item has an input field showing its text. After deleting the 2nd item, the 3rd item's input shows the 2nd item's text.
Using `index` as the key means when item 2 is deleted, React thinks item 3 IS item 2 (same key=2). It reuses the old component instance (with stale state) instead of destroying item 2 and moving item 3.
Use a stable unique ID (e.g., `todo.id`) as the key. Now React correctly identifies which component was removed and which should be kept. The reconciliation algorithm can match by identity instead of position.
Takeaway: The reconciliation algorithm's O(n) shortcut relies entirely on keys for list matching. Using array index as key defeats this optimization and introduces state bugs whenever order changes.
You have a conditional render: `isAdmin ? <AdminPanel /> : <UserPanel />`. Switching between admin and user views causes a full re-mount, destroying all form state.
React's reconciliation sees a different component TYPE at the same position. Its heuristic: 'different type = completely different tree'. It destroys the old subtree and builds a new one from scratch β losing all internal state.
If both panels share a similar structure, use the same component with conditional rendering inside. Or use `key` to explicitly control when a component should re-mount vs update. Understanding that React compares types first, then props, helps you design state-preserving UIs.
Takeaway: React's reconciliation compares elements top-down: type first, then key, then props. A type change always triggers a full unmount/remount of the entire subtree β this is by design, not a bug.