Common React Context Mistakes

Common React Context Mistakes

Performance guide and best practices to avoid cascading re-renders

React's Context API is powerful for sharing data across an application. But when misused, it causes cascading re-renders, degrades performance and makes code hard to evolve.

đź”´Most Frequent Mistakes

1. God Context Anti-Pattern

Grouping everything (auth, theme, preferences, data) in a single context. Any state change triggers all consuming components, even if they only need a fraction of the data.

❌ Bad: <AppContext.Provider value={{ user, theme, settings, cart, notifications, ... }}>

âś… Good: AuthContext + ThemeContext + SettingsContext + CartContext

2. Volatile High-Frequency State

Storing high-frequency values (form inputs, real-time data, scroll position) in Context. Every keystroke or update triggers re-renders of all consumers.

❌ Bad: Storing searchInput in Context (re-render on every keystroke)

âś… Good: Local state with useState or uncontrolled input with useRef

3. useContext Everywhere

Using Context for everything instead of props or lifting state closer to where it's needed. Context is not a replacement for good component architecture.

❌ Bad: Passing modalState via Context to 2 sibling components

âś… Good: Lift state to parent and pass as props

4. Unstable References

Creating new objects or functions in Provider without memoization. Every render creates new references, triggering re-renders of all consumers.

❌ Bad: value={{ user, login: () => {...} }}

âś… Good: value={useMemo(() => ({ user, login }), [user])}

5. Coupled Read/Write

Mixing state and mutations in the same context. Components that only need actions are forced to re-render when state changes.

❌ Bad: value={{ todos, addTodo, deleteTodo }} (re-renders all consumers on state change)

âś… Good: Separate TodosContext (state) and TodosAPIContext (actions)

âś…Best Practices

1. Specialized Contexts

Split your contexts by domain: AuthContext, ThemeContext, SettingsContext, CartContext. Each component only subscribes to what it needs.

2. Dual Context Pattern

Separate API (stable functions) and State (mutable data) into two contexts:

  • Context A (API): Stable functions, never re-renders
  • Context B (State): Mutable data, only re-renders state consumers
  • Result: Components that act import API, those that display import State

3. Memoization

Stabilize objects and functions with useMemo/useCallback to avoid creating new references on every render.

4. Props for Local State

Don't use Context if only 2-3 close components need the data. Props are simpler, more explicit and more performant.

5. Co-locate State

Keep state as close as possible to consuming components. Don't lift it to Context unless truly necessary.

🔵Dual Context Pattern in Detail

Context A: API (Actions)

  • •Stable functions (login, logout, updateTheme...)
  • •Never re-renders consuming components
  • •Wrapped with useCallback to ensure stability
  • •Imported by components that perform actions

Context B: State (Data)

  • •Mutable data (user, theme, cart...)
  • •Re-renders only components consuming this state
  • •Optimized with useMemo if object/array
  • •Imported by components that display data

Result:

Components that perform actions import the API context and never re-render on state changes. Components that display data import the State context and only re-render when that specific state changes.

When to Use (or Not Use) Context

âś… Good Use Cases

  • • Global data (auth, theme, locale)
  • • Data consumed by many distant components
  • • Avoiding prop drilling (5+ levels)
  • • Stable configurations
  • • User preferences

❌ Bad Use Cases

  • • Volatile high-frequency state (inputs)
  • • Real-time data (websockets, intervals)
  • • Data for only 2-3 close components
  • • As state management replacement
  • • Complex state logic (use Zustand, Jotai)

Performance Checklist

  • Split God Context into specialized contexts by domain
  • Separate API and State into Dual Context pattern
  • Memoize context values with useMemo/useCallback
  • Remove volatile state from Context (use local state)
  • Verify no unnecessary useContext calls (use props if close)
  • Test performance with React DevTools Profiler
  • Consider state library (Zustand, Jotai) for complex logic

Need Help Optimizing Your React Application?

VOID's React experts audit and optimize your architecture for maximum performance

🌱Eco-designed site