The complete guide to React Diffing algorithms
1. Overview of Diffing Algorithm
1.1 What is Diffing
The Diffing algorithm is a algorithm used by React to compare the differences between two virtual DOM trees. It is used to determine the parts that need to be updated to minimize DOM operations.
1.2 Basic Principles
- Different types of elements will produce different trees
- Identify which child elements remain stable in different renderings through the key attribute
- Adopt the same-level comparison strategy
2. Detailed explanation of Diffing strategy
2.1 Element type comparison
// Comparison of different types of elements// Old tree<div> <Counter /> </div> // New Tree<span> <Counter /> </span> // React Will completely delete the old tree,Rebuild a new tree
2.2 Comparison of elements of the same type
// Comparison of DOM elements of the same type// Old tree<div className="old" title="old"> Hello </div> // New Tree<div className="new" title="new"> World </div> // React Only change attributes will be updated
2.3 Component comparison
class MyComponent extends { render() { // Only rendering results are compared when updated return ( <div> <h1>{}</h1> <p>{}</p> </div> ); } }
3. List Diffing
3.1 No key
// Low-efficient list renderingfunction ListWithoutKeys() { return ( <ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> ); } // When the list item changes,React Need to re-render all items
3.2 Optimization using key
// Rendering list using keyfunction ListWithKeys() { const items = [ { id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }, { id: 3, text: 'Item 3' } ]; return ( <ul> {(item => ( <li key={}>{}</li> ))} </ul> ); } // React Can be passed key Identify which elements remain the same
3.3 Best Practices for Keys
// Not recommended: Use index as keyconst BadList = () => ( <ul> {((item, index) => ( <li key={index}>{}</li> ))} </ul> ); // Recommended: Use a stable unique identifier as keyconst GoodList = () => ( <ul> {(item => ( <li key={}>{}</li> ))} </ul> );
4. Diffing algorithm implementation principle
4.1 Tree traversal strategy
function diffTree(oldTree, newTree) { if (oldTree === null) { // Insert a new node return createNode(newTree); } if (newTree === null) { // Delete old nodes return null; } if ( !== ) { // Replace node return createNode(newTree); } // Update existing nodes updateNode(oldTree, newTree); // Recursively process child nodes diffChildren(, ); }
4.2 Sub-node comparison algorithm
function diffChildren(oldChildren, newChildren) { // The first round: processing updated nodes for (let i = 0; i < (, ); i++) { diff(oldChildren[i], newChildren[i]); } // Handle new nodes if ( > ) { ().forEach(child => { create(child); }); } // Handle deleted nodes if ( > ) { ().forEach(child => { remove(child); }); } }
5. Performance optimization strategy
5.1 Avoid unnecessary rendering
class OptimizedComponent extends { shouldComponentUpdate(nextProps, nextState) { // Update only if necessary return !== ; } render() { return <div>{}</div>; } } // Use Optimize Function Componentsconst MemoizedComponent = (function MyComponent(props) { return <div>{}</div>; });
5.2 List optimization
// Use key and memo to optimize list renderingconst OptimizedListItem = (({ item }) => ( <li>{}</li> )); function OptimizedList({ items }) { return ( <ul> {(item => ( <OptimizedListItem key={} item={item} /> ))} </ul> ); }
5.3 Large list virtualization
import { FixedSizeList } from 'react-window'; function VirtualizedList({ items }) { const Row = ({ index, style }) => ( <div style={style}> {items[index].text} </div> ); return ( <FixedSizeList height={400} width={300} itemCount={} itemSize={35} > {Row} </FixedSizeList> ); }
6. FAQs and Solutions
6.1 key related issues
// Problem: Re-rendering caused by key instabilityconst ProblematicList = () => ( <ul> {((item, i) => ( <li key={()}>{}</li> // Don't do this ))} </ul> ); // Solution: Use stable unique identifierconst FixedList = () => ( <ul> {(item => ( <li key={}>{}</li> ))} </ul> );
6.2 Unnecessary re-rendering
// Problem: Parent component update causes unnecessary re-rendering of child componentsconst Parent = () => { const [count, setCount] = useState(0); return ( <div> <button onClick={() => setCount(count + 1)}> Count: {count} </button> <Child data={data} /> // Child will re-render even if data does not change </div> ); }; // Solution: Use useMemo orconst Parent = () => { const [count, setCount] = useState(0); const memoizedData = useMemo(() => data, [data]); return ( <div> <button onClick={() => setCount(count + 1)}> Count: {count} </button> <Child data={memoizedData} /> </div> ); };
7. Summary
7.1 Key points of Diffing algorithm
- Adopt the same-level comparison strategy
- Different types of elements produce different trees
- The importance of key attributes
- Component stability
7.2 Optimization suggestions
- Use keys reasonably
- Avoid unnecessary nesting
- Using immutable data structures
- Use memo and useMemo appropriately
- Large list consider virtualization
7.3 Best Practices
- Keep the components pure
- Reasonably split components
- Use key correctly
- Avoid deep component trees
- Timely performance optimization
8. Classic interview questions
What is the function of the key in /vue? (What is the internal principle of key?)
2. Why is it better not to use index when traversing the list?
1. The role of key in virtual DOM:
Simply put: the key is the identifier of the virtual DOM object, and the key plays an extremely important role when updating the display.
To put it in detail: When the data in the state changes, react will generate [new virtual DOM] based on [new data], and then React compares the diff between [new virtual DOM] and [old virtual DOM]. The comparison rules are as follows:
a. The same key as the new virtual DOM was found in the old virtual DOM:
(1). If the content in the virtual DOM has not changed, use the previous real DOM directly
(2). If the content in the virtual DOM changes, a new real DOM is generated, and then the previous real DOM in the page is replaced.
b. The same key as the new virtual DOM is not found in the old virtual DOM. Create a new real DOM based on the data, and then render to the page
2. Problems that may be caused by using indexf as key:
1. If you perform destructive operations such as: reverse order addition, reverse order deletion, etc. on the data: unnecessary real DOM updates will be generated ==>The interface effect is no problem, but the effect is half low.
2. If the structure also contains the DOM of the input class: an error will be generated. There is a problem with the interface ==>.
3. Note! If there are no destructive operations such as reverse order addition and reverse order deletion of data, it is only used for rendering lists for display. There is no problem using index as key.
3. How to choose key in development?:
1. It is best to use the unique identifier of each piece of data as the key, such as the unique value of id, mobile phone number, ID number, student number, etc.
2. If you are sure that it is just a simple display of data, you can also use index.
This is all about this article about the complete guide to React Diffing algorithm. For more related React Diffing algorithm content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!