How patching and diffing works in react
React generates a set of operations to update the actual DOM through a process known as reconciliation, which involves several key steps:
1. Initial Rendering
When a React component is rendered for the first time, React creates a virtual DOM tree. The virtual DOM is a lightweight, in-memory representation of the actual DOM.
2. Virtual DOM Comparison (Diffing)
When the state or props of a component change, React re-renders the component, producing a new virtual DOM tree. React then compares this new virtual DOM tree with the previous virtual DOM tree to determine what has changed. This comparison process is called diffing.
3. Identifying Changes
During the diffing process, React identifies the differences between the new and old virtual DOM trees. These differences include:
- Element Changes: If an element has been added, removed, or replaced.
- Attribute Changes: If the attributes or properties of an element have changed.
- Text Changes: If the text content of an element has changed.
4. Generating Patches
Based on the identified differences, React generates a set of instructions (patches) that describe the minimal set of changes needed to update the actual DOM. These patches include:
- Creating: Instructions to create new elements.
- Updating: Instructions to update attributes, properties, or text content of existing elements.
- Removing: Instructions to remove elements that are no longer needed.
5. Applying Patches to the DOM
React applies these patches to the actual DOM in the most efficient way possible. This step involves:
- Batching Updates: React batches multiple updates together to minimize the number of reflows and repaints, which can be expensive operations for the browser.
- Efficient DOM Manipulation: By applying only the necessary changes, React avoids the performance overhead associated with manipulating the DOM directly.
Example
Consider a simple React component that displays a list of items. When an item is added, React needs to update the DOM to reflect the new list:
import React, { useState } from 'react';
function ItemList() {
const [items, setItems] = useState(['Item 1', 'Item 2', 'Item 3']);
const addItem = () => {
setItems([...items, `Item ${items.length + 1}`]);
};
return (
<div>
<ul>
{items.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
<button onClick={addItem}>Add Item</button>
</div>
);
}
export default ItemList;
Steps During an Update
-
Initial Render:
- Initial virtual DOM tree is created.
- Actual DOM is updated to match the virtual DOM.
-
State Change:
- User clicks "Add Item" button.
- State changes, triggering a re-render.
- New virtual DOM tree is created.
-
Diffing:
- React compares the new virtual DOM tree with the previous one.
- Identifies that a new
<li>
element has been added.
-
Generating Patches:
- React generates a patch to add the new
<li>
element.
- React generates a patch to add the new
-
Applying Patches:
- React applies the patch, updating the actual DOM to include the new item.
Visual Representation
Here's a simplified visual representation of the diffing and patching process:
-
Previous Virtual DOM:
<ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul>
-
New Virtual DOM:
<ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> </ul>
-
Diffing Result:
- New
<li>Item 4</li>
element detected.
- New
-
Patch Generated:
+ <li>Item 4</li>
-
Actual DOM Update:
- New
<li>
element is added to the actual DOM.
- New