š What is Reconciliation?
š Definition
Reconciliation is the algorithm React uses to diff one tree with another to determine which parts need to be changed. It's the process of comparing the new Virtual DOM tree with the previous Virtual DOM tree and determining the minimal set of changes needed to update the real DOM.
šļø Real-World Analogy
Architect's Blueprint
Compare old building plans with new renovation plans
Identify Changes
Find what rooms need modification, addition, or removal
Minimal Construction
Only make necessary changes to the actual building
šÆ Key Concepts
Tree Diffing
Compares two tree structures node by node
Key-based Matching
Uses keys to identify and track elements
Minimal Updates
Applies only necessary changes to the DOM
Heuristic Approach
Uses assumptions to optimize performance
āļø The Reconciliation Process
š Step-by-Step Process
State Change Triggers Re-render
Component state or props change, triggering a re-render
setState({ count: count + 1 });
Create New Virtual DOM Tree
React creates a new Virtual DOM representation
Diff Algorithm Comparison
Compare old and new Virtual DOM trees
Generate Update Instructions
Create a list of minimal changes needed
Apply Changes to Real DOM
Execute the minimal set of DOM operations
š® Interactive Process Demo
š Diffing Algorithm Rules
šÆ Core Assumptions
React's diffing algorithm makes several assumptions to achieve O(n) complexity instead of O(n³):
Different Element Types
Elements of different types will produce different trees
Before:
<div><Counter /></div>
After:
<span><Counter /></span>
Result:
Complete rebuild of subtreeKey Prop Stability
Elements with stable keys will be preserved across renders
Before:
<li key="1">Item A</li>
<li key="2">Item B</li>
After:
<li key="2">Item B</li>
<li key="1">Item A</li>
Result:
Reorder existing elementsRecursive Children Diffing
When diffing children, React compares them recursively
Before:
<ul>
<li>A</li>
<li>B</li>
</ul>
After:
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
Result:
Insert new <li>C</li> at endš® Rules Visualization Demo
Before
After
š Keys Deep Dive
šÆ Why Keys Matter
Keys help React identify which items have changed, are added, or are removed. They give elements a stable identity across renders.
ā Bad: Using Array Index
{items.map((item, index) =>
<TodoItem key={index} todo={item} />
)}
Problems:
- Keys change when list is reordered
- Component state gets mixed up
- Unnecessary re-renders
- Performance degradation
ā Good: Using Stable IDs
{items.map(item =>
<TodoItem key={item.id} todo={item} />
)}
Benefits:
- Stable identity across renders
- Preserved component state
- Efficient reordering
- Better performance
š® Keys Behavior Demo
Using Array Index as Key
Using Stable ID as Key
š Performance Comparison
Perform operations above to see the performance difference!
š Component Lifecycle in Reconciliation
š Lifecycle Methods During Reconciliation
Understanding which lifecycle methods are called during different reconciliation scenarios:
š Component Mount
When a new element is added to the Virtual DOM tree
š Component Update
When props or state change but element type remains same
šļø Component Unmount
When element is removed from Virtual DOM tree
š Element Type Change
When element type changes (e.g., div ā span)
š® Lifecycle Tracking Demo
Component State
No component mounted
Lifecycle Log
ā” Performance Optimizations
šÆ Reconciliation Optimizations
Techniques to make reconciliation more efficient and avoid unnecessary re-renders:
React.memo()
Memoizes component to prevent re-renders when props haven't changed
const MemoizedComponent = React.memo(function MyComponent(props) {
return <div>{props.name}</div>;
});
// Only re-renders if props.name changes
useMemo() Hook
Memoizes expensive calculations to avoid recalculating on every render
const expensiveValue = useMemo(() => {
return heavyCalculation(props.data);
}, [props.data]);
// Only recalculates when props.data changes
useCallback() Hook
Memoizes functions to prevent child re-renders
const handleClick = useCallback(() => {
setCount(count + 1);
}, [count]);
// Function reference stays same if count unchanged
Proper Key Usage
Use stable, unique keys for list items
// ā
Good
{items.map(item =>
<Item key={item.id} data={item} />
)}
// ā Bad
{items.map((item, index) =>
<Item key={index} data={item} />
)}
š® Performance Optimization Demo
ā Unoptimized Component
ā Optimized Component
š Performance Comparison
Interact with both versions to see the difference!
ā ļø Common Reconciliation Pitfalls
šØ Avoid These Common Mistakes
Understanding these pitfalls will help you write more efficient React applications:
Using Index as Key
ā Problem:
{items.map((item, index) =>
<Item key={index} data={item} />
)}
Keys change when list is reordered, causing unnecessary re-renders and state loss.
ā Solution:
{items.map(item =>
<Item key={item.id} data={item} />
)}
Use stable, unique identifiers as keys.
Creating Objects in Render
ā Problem:
function Parent() {
return <Child config={{ theme: 'dark' }} />;
}
New object created on every render, causing child to always re-render.
ā Solution:
const config = { theme: 'dark' };
function Parent() {
return <Child config={config} />;
}
Move object outside component or use useMemo.
Inline Function Props
ā Problem:
<Button onClick={() => handleClick(id)} />
New function created on every render, breaking memoization.
ā Solution:
const handleButtonClick = useCallback(
() => handleClick(id), [id]
);
<Button onClick={handleButtonClick} />
Use useCallback to memoize the function.
Conditional Rendering Issues
ā Problem:
{showHeader && <Header />}
<Content />
{showFooter && <Footer />}
Changing conditions can cause position shifts and unnecessary re-renders.
ā Solution:
<Header style={{ display: showHeader ? 'block' : 'none' }} />
<Content />
<Footer style={{ display: showFooter ? 'block' : 'none' }} />
Use CSS to hide/show instead of conditional rendering when appropriate.
š® Pitfalls Demonstration
ā Problematic Code
// Select a pitfall to see the problem
ā Fixed Code
// Click "Show Solution" to see the fix
š” Impact Analysis
šÆ Best Practices & Summary
š” Reconciliation Best Practices
Use Stable Keys
- Use unique, stable identifiers
- Avoid array indices for dynamic lists
- Keep keys consistent across renders
Optimize with Memoization
- Use React.memo for component memoization
- Apply useMemo for expensive calculations
- Use useCallback for stable function references
Structure Components Wisely
- Keep component trees shallow
- Split large components into smaller ones
- Avoid deep nesting when possible
Monitor Performance
- Use React DevTools Profiler
- Identify unnecessary re-renders
- Measure before and after optimizations
šÆ Key Takeaways
Reconciliation Process
React compares Virtual DOM trees to determine minimal changes needed for the real DOM, making updates efficient and predictable.
Performance Impact
Proper key usage and memoization techniques can dramatically improve reconciliation performance and user experience.
Developer Control
Understanding reconciliation helps developers write more efficient components and avoid common performance pitfalls.
Future Improvements
React Fiber and Concurrent Features build upon reconciliation concepts to enable even better performance and user experience.