Reconciliation and Diffing
Reconciliation is React's process for matching the previous UI tree with the next UI tree.
Diffing is the comparison step inside that process.
The Core Idea
When state changes, React calls components again.
function Status({ isOnline }) {
return <p>{isOnline ? "Online" : "Offline"}</p>;
}If isOnline changes, React compares:
<p>Offline</p>with:
<p>Online</p>The element type is still p, so React can keep the same DOM node and update its text.
Element Type Matters
If the element type changes, React usually treats it as a different subtree.
function Message({ important }) {
if (important) {
return <strong>Read this</strong>;
}
return <span>Read this</span>;
}Switching from span to strong means React replaces that DOM element.
The same idea applies to components.
{mode === "edit" ? <EditForm /> : <ReadOnlyView />}Changing component types can unmount one component and mount another, which resets state inside that subtree.
Position Matters
React matches children by their position unless keys tell it otherwise.
function Toolbar({ isAdmin }) {
return (
<div>
{isAdmin && <button>Delete</button>}
<button>Save</button>
</div>
);
}When isAdmin changes from false to true, the Save button shifts from the first child position to the second. For simple DOM nodes this may be fine, but for stateful components position changes can reset or move state in surprising ways.
Keys help React understand identity in lists and changing sets of children.
Keys and Identity
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} />
))}
</ul>
);
}The key tells React that the item with id todo-7 is the same logical item even if it moves to another position.
Keys are not passed as normal props.
function TodoItem({ todo }) {
// There is no props.key here.
return <li>{todo.text}</li>;
}If the component needs the id, pass it explicitly.
<TodoItem key={todo.id} id={todo.id} todo={todo} />State Preservation and Reset
React preserves component state when the same component type stays in the same position.
{isCompact ? <SearchBox /> : <SearchBox />}This preserves SearchBox state because both branches produce the same component type in the same place.
To intentionally reset state, change the key.
<ProfileForm key={user.id} user={user} />When user.id changes, React treats it as a different ProfileForm instance and resets its internal state.
Common Mistakes
- Assuming React matches elements by visual similarity instead of type, position, and key.
- Using array indexes as keys for lists that can reorder or delete items.
- Expecting a component's state to reset when props change. Props changing does not automatically reset local state.
- Forgetting that switching component types unmounts one subtree and mounts another.
- Trying to read
keyinside the child component as a normal prop.
What is the main purpose of keys during reconciliation?
Practice Challenge
You have a tabbed profile page:
<ProfileEditor user={selectedUser} />The editor has local draft state. When selectedUser changes, the draft should reset.
Update the JSX so React treats each selected user as a distinct editor instance. Then explain why the change works.
Recap
Reconciliation matches old and new UI trees. React preserves or replaces DOM and component state based on element type, position, and keys.