Introduction to React Rendering
Rendering is the process where React executes a component and creates (or updates) its Virtual DOM representation. React then compares it with the previous version and updates only the necessary parts of the real DOM.
There are two types of rendering:
- Initial Render: The component renders for the first time.
- Re-render: The component renders again when its data changes.
A re-render does not always mean the real DOM is updated. React first compares the new Virtual DOM with the previous one.
React Rendering Process
Whenever a component’s state or props change, React follows these steps:
- Execute the component function.
- Create a new Virtual DOM tree.
- Compare it with the previous Virtual DOM (Reconciliation).
- Identify the differences (Diffing).
- Update only the affected parts of the real DOM.
- The browser repaints the updated UI.
We need to minimize expensive DOM operations.
React Fiber and Rendering
React Fiber is React’s rendering engine introduced in React 16.
It improves rendering by:
- Breaking rendering work into smaller units.
- Prioritizing important updates.
- Pausing and resuming rendering.
- Supporting concurrent rendering.
Benefit: Keeps the UI responsive during complex updates.
Reconciliation Algorithm
Reconciliation is React’s process of comparing the old Virtual DOM with the new Virtual DOM to determine what has changed.
Instead of rebuilding the entire UI, React:
- Compares element types.
- Compares component props.
- Matches list items using
key. - Updates only the changed nodes.
This makes UI updates efficient.
What Triggers a Re-render?
A component re-renders when:
- Its state changes (
useState,useReducer). - Its props change.
- A Context value it consumes changes.
- Its parent re-renders (React evaluates the child again; optimizations like
React.memomay allow React to skip committing an update). - It is forcefully updated (rare in modern React).
Not every re-render results in a DOM update.
What Does NOT Trigger a Re-render?
Some changes don’t cause React to render again:
- Updating a
useRefvalue. - Modifying local variables.
- Changing object properties without updating state.
- Reading browser APIs.
These values exist outside React’s rendering cycle.
Types of Re-renders
Expected Re-render
Occurs when the UI genuinely needs updating.
Example: Clicking a counter button updates the count.
Unnecessary Re-render
Occurs when a component renders even though its output hasn’t changed.
Example: A parent re-renders and a child with unchanged props also renders.
Expensive Re-render
Occurs when rendering itself is computationally heavy.
Example: Rendering thousands of rows or performing expensive calculations on every render.
Causes of Unnecessary Re-renders
Common reasons include:
- Parent component re-renders.
- Creating new object or array literals in JSX.
- Creating new callback functions on each render.
- Context updates affecting many consumers.
- Large components that handle too many responsibilities.
- Unstable keys in lists.
Recognizing these patterns is the first step toward optimization.
Optimization Techniques
React provides several ways to reduce unnecessary work:
- React.memo() skips re-rendering when props are unchanged.
- useMemo() caches expensive computed values.
- useCallback() caches function references.
- useRef() stores mutable values without causing re-renders.
- Component splitting isolates updates.
- Local state limits the impact of changes.
- Context optimization reduces unnecessary context-driven renders.
- List virtualization renders only visible items.
- Lazy loading and code splitting reduce the initial JavaScript bundle.
Each technique targets a different source of unnecessary work.
Choosing the Right Optimization
Rather than applying every optimization, match the technique to the problem:
- Expensive calculations → useMemo
- Changing function references → useCallback
- Child components re-rendering unnecessarily → React.memo
- Large lists → Virtualization
- Large bundles → Lazy loading / Code splitting
- Broad context updates → Split or optimize Context
- Unnecessary global state → Keep state local
Using the appropriate optimization keeps the codebase simpler and avoids premature optimization.
Best Practices
- Keep state as close as possible to where it’s used.
- Avoid creating new objects, arrays, and functions unnecessarily.
- Use
React.memo,useMemo, anduseCallbackonly when they provide measurable benefits. - Split large components into smaller, focused ones.
- Use stable keys (IDs instead of array indexes when possible).
- Virtualize large lists instead of rendering everything.
- Profile your application before optimizing.
