0
0
ReactDebug / FixBeginner · 4 min read

Avoid Unnecessary Re-renders with Context in React: Simple Fixes

To avoid unnecessary re-renders with React Context, keep context values stable by memoizing them with useMemo and split context into smaller pieces if possible. This prevents all components consuming the context from re-rendering when unrelated parts of the context change.
🔍

Why This Happens

React re-renders all components consuming a context whenever the context value changes. If you provide an object or array directly in the context provider without memoization, it creates a new reference on every render, causing all consumers to re-render even if the data they use did not change.

jsx
import React, { createContext, useState } from 'react';

const MyContext = createContext();

function MyProvider({ children }) {
  const [count, setCount] = useState(0);
  const value = { count, setCount }; // New object every render

  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
}

function Display() {
  const { count } = React.useContext(MyContext);
  console.log('Display rendered');
  return <div>Count: {count}</div>;
}

function App() {
  return (
    <MyProvider>
      <Display />
    </MyProvider>
  );
}

export default App;
Output
Display rendered Display rendered Display rendered ... (renders on every parent render even if count is unchanged)
🔧

The Fix

Use React.useMemo to memoize the context value so it only changes when its contents change. This keeps the reference stable and prevents unnecessary re-renders. Also, consider splitting context into smaller contexts if you have unrelated data.

jsx
import React, { createContext, useState, useMemo } from 'react';

const MyContext = createContext();

function MyProvider({ children }) {
  const [count, setCount] = useState(0);

  const value = useMemo(() => ({ count, setCount }), [count]);

  return <MyContext.Provider value={value}>{children}</MyContext.Provider>;
}

function Display() {
  const { count } = React.useContext(MyContext);
  console.log('Display rendered');
  return <div>Count: {count}</div>;
}

function App() {
  return (
    <MyProvider>
      <Display />
    </MyProvider>
  );
}

export default App;
Output
Display rendered Display rendered (only when count changes)
🛡️

Prevention

To avoid this issue in the future:

  • Always memoize context values with useMemo or useCallback when passing objects or functions.
  • Split large context objects into smaller, focused contexts to reduce re-renders.
  • Use React DevTools Profiler to spot unnecessary renders.
  • Consider using selectors or custom hooks to consume only needed parts of context.
⚠️

Related Errors

Similar issues include:

  • Prop drilling causing re-renders: Fix by using context or memoization.
  • Unstable callback functions: Fix by wrapping callbacks with useCallback.
  • State updates causing full tree re-renders: Fix by splitting state or using memoized selectors.

Key Takeaways

Memoize context values with useMemo to keep references stable and avoid re-renders.
Split context into smaller parts to limit re-renders to only components that need updates.
Use React DevTools Profiler to identify unnecessary re-renders.
Wrap functions passed in context with useCallback to prevent new references.
Consume only needed context data with custom hooks or selectors.