Reconciliation Algorithm
React’s child reconciler compares children produced by a component with existing child fibers and returns the fiber sequence for the next render. Its central implementation is ReactChildFiber.js, where single children, arrays, iterators, text, elements, portals, and lazy values take different reconciliation paths.
This code exists to preserve child identity when possible, mark insertions and moves, and record deletions when the new child structure no longer matches the old one. Keys provide the lookup signal used to associate children with existing fibers.
Sources: packages/react-reconciler/src/ReactChildFiber.js:2015-2086, packages/react-reconciler/src/ReactChildFiber.js:1835-2013, packages/react-reconciler/src/ReactChildFiber.js:1658-1686, packages/react-reconciler/src/ReactChildFiber.js:498-528, packages/react-reconciler/src/ReactChildFiber.js:421-433, packages/react-reconciler/src/ReactChildFiber.js:827-968
Core concepts
Child identity
A child is reusable when its key and compatible type match the existing fiber; otherwise the reconciler creates a new fiber.
Sources: packages/react-reconciler/src/ReactChildFiber.js:827-968, packages/react-reconciler/src/ReactChildFiber.js:567-621
Stable keys
A stable key is a value used to find the same logical child across renders; the remaining-child map supports string, number, and optimistic-key entries.
Sources: packages/react-reconciler/src/ReactChildFiber.js:454-487, packages/react-reconciler/src/ReactChildFiber.js:970-1102
Placement
Placement is the step that records whether a fiber is newly inserted, moved, or able to remain in place.
Sources: packages/react-reconciler/src/ReactChildFiber.js:498-528
Fast path
The fast path handles a single element, portal, or text node without running the array matching algorithm.
Sources: packages/react-reconciler/src/ReactChildFiber.js:1835-2013, packages/react-reconciler/src/ReactChildFiber.js:1658-1686, packages/react-reconciler/src/ReactChildFiber.js:1688-1787, packages/react-reconciler/src/ReactChildFiber.js:1789-1830
Slow path
The slow path builds a temporary map of remaining old children so later new children can be matched by key or, for unkeyed children, by index.
Sources: packages/react-reconciler/src/ReactChildFiber.js:454-487, packages/react-reconciler/src/ReactChildFiber.js:970-1102
How reconciliation chooses a path
reconcileChildFibers resets per-reconciliation state, calls reconcileChildFibersImpl, clears thenableState after success, and restores debug information in a finally block.
The implementation treats a top-level array as a set of children, dispatches arrays to reconcileChildrenArray, and dispatches iterables to reconcileChildrenIteratable; a single element or portal instead uses its dedicated single-child reconciler.
| Child shape | Reconciliation entry point | Main identity rule |
|---|---|---|
| Single text | reconcileSingleTextNode | Reuse an existing HostText fiber |
| Single element | reconcileSingleElement | Match key, then compatible element type |
| Single portal | reconcileSinglePortal | Match key, portal container, and implementation |
| Array | reconcileChildrenArray | Match slots first, then remaining children by map |
A single element uses reconcileSingleElement, then placeSingleChild; this helper marks placement only when side effects are tracked and the fiber has no alternate.
Evidence
- child-reconcilerpackages/react-reconciler/src/ReactChildFiber.js:2015
- impl-dispatchpackages/react-reconciler/src/ReactChildFiber.js:1835
- single-elementpackages/react-reconciler/src/ReactChildFiber.js:1688
- single-placementpackages/react-reconciler/src/ReactChildFiber.js:530
The sequence follows the calls from reconcileChildFibersImpl through reconcileSingleElement and placeSingleChild.
Sources: packages/react-reconciler/src/ReactChildFiber.js:2015-2086, packages/react-reconciler/src/ReactChildFiber.js:1835-2013, packages/react-reconciler/src/ReactChildFiber.js:1658-1686, packages/react-reconciler/src/ReactChildFiber.js:1688-1787, packages/react-reconciler/src/ReactChildFiber.js:1789-1830, packages/react-reconciler/src/ReactChildFiber.js:1162-1354, packages/react-reconciler/src/ReactChildFiber.js:530-537
Why keys preserve list identity
The first array pass advances through old and new children together. For each position it calls updateSlot, which returns null when the old and new keys do not match; matching element keys proceed to updateElement.
When an old child has no explicit key, mapRemainingChildren stores that fiber under its index. This gives the slow path an index-based lookup for unkeyed children.
With explicit keys, the remaining-child map stores fibers under those keys, and updateFromMap looks up a new element by its key; a null key instead uses the new index.
Development mode warns when an element or portal has no key and reports duplicate string keys. The duplicate-key warning says that keys should be unique so components maintain identity across updates; non-unique keys may cause children to be duplicated or omitted.
Stable keys therefore matter because they give the reconciler a reusable identity signal rather than requiring every remaining child to be represented only by its position. Duplicate keys make that signal ambiguous and may produce duplicated or omitted children.
Sources: packages/react-reconciler/src/ReactChildFiber.js:1162-1354, packages/react-reconciler/src/ReactChildFiber.js:827-968, packages/react-reconciler/src/ReactChildFiber.js:454-487, packages/react-reconciler/src/ReactChildFiber.js:970-1102, packages/react-reconciler/src/ReactChildFiber.js:1107-1160
How the array diff makes two passes
The array algorithm first performs a forward slot pass. It compares old and new children at the current position, validates keys, records a deletion if a matched slot produced a new fiber, and calls placeChild to classify the result.
If the new array ends first, the reconciler deletes the remaining old children. If the old children end first, the remaining new children use an insertion-only path that calls createChild.
When the forward pass encounters a mismatch while old children remain, the remaining old fibers are indexed with mapRemainingChildren. Later new children are resolved through updateFromMap, then placed and linked into the resulting child sequence.
Evidence
- array-entrypackages/react-reconciler/src/ReactChildFiber.js:1162
- slot-passpackages/react-reconciler/src/ReactChildFiber.js:827
- slot-passpackages/react-reconciler/src/ReactChildFiber.js:1196
- remaining-mappackages/react-reconciler/src/ReactChildFiber.js:454
- map-passpackages/react-reconciler/src/ReactChildFiber.js:970
- placementpackages/react-reconciler/src/ReactChildFiber.js:498
- deletionspackages/react-reconciler/src/ReactChildFiber.js:435
The workflow shows the two array phases and their state changes: slot matching, keyed or indexed lookup, placement marking, and deletion recording.
placeChild records the new index, marks a reused fiber as a move when its old index is behind lastPlacedIndex, leaves an in-order fiber in place, and marks a new fiber with Placement when it is inserted.
Deletions are stored on the parent fiber: the first deletion initializes returnFiber.deletions and sets ChildDeletion, while later deletions are appended.
Sources: packages/react-reconciler/src/ReactChildFiber.js:1196-1249, packages/react-reconciler/src/ReactChildFiber.js:1251-1262, packages/react-reconciler/src/ReactChildFiber.js:1162-1354, packages/react-reconciler/src/ReactChildFiber.js:454-487, packages/react-reconciler/src/ReactChildFiber.js:970-1102, packages/react-reconciler/src/ReactChildFiber.js:498-528, packages/react-reconciler/src/ReactChildFiber.js:435-452, packages/react-reconciler/src/ReactChildFiber.js:421-433
How it connects
The reconciler returns child fibers to the render phase, where the work-in-progress tree is built and later handed to commit logic; this page covers child matching and flags, not later host mutation. The broader render hand-off is described in Render Phase and host mutations in Commit Phase.
The resulting fiber identity participates in the double-buffered Fiber model described in Fiber Architecture. Reconciliation is invoked as part of scheduled rendering, connecting it to Work Loop & Scheduling.
Sources: packages/react-reconciler/src/ReactChildFiber.js:498-528, packages/react-reconciler/src/ReactChildFiber.js:421-433, packages/react-reconciler/src/ReactChildFiber.js:2015-2086
Key takeaways
- Single children use dedicated text, element, or portal paths; arrays use
reconcileChildrenArray. - Keys let the reconciler look up logical children by key instead of only by index.
- Duplicate keys can cause children to be duplicated or omitted.
- Array reconciliation has two passes: forward slot matching, then keyed or indexed map lookup.
- Placement flags distinguish moves and insertions, while deletions are recorded on the parent fiber.