Redux vs React Context
"Should we use Redux or Context?" is one of the most common React architecture questions — and it compares two different kinds of tools. React Context is a mechanism for passing a value down the component tree without threading props through every level. It does not manage state by itself; whatever state you put in it still lives in useState or useReducer somewhere. Redux (in its modern form, Redux Toolkit) is a state management library: a single store outside React, updated by dispatched actions through reducers, with selective subscriptions, middleware, and powerful developer tools.
Short verdict: use Context for values that change rarely and are needed widely — theme, locale, the current user, feature flags, dependency injection. Use Redux Toolkit (or a lighter store such as Zustand) for complex, frequently updated client state shared across many components. Use a server-state library for data from APIs, whichever you choose. Most "Redux vs Context" debates disappear once server state moves to TanStack Query or RTK Query.
TL;DR
- Context passes values down the tree; it is not a state manager and has no selectors.
- Every consumer of a context re-renders when its value changes, even if it uses only part of it.
- Redux Toolkit keeps state in an external store;
useSelectorre-renders components only when their selected data changes. - Redux adds DevTools time travel, middleware, predictable updates, and structure that scales across large teams.
- Server state (API data) belongs in TanStack Query or RTK Query, not hand-rolled in either.
- Lighter stores — Zustand, Jotai — offer selector-based subscriptions with much less ceremony.
Quick Example
Context is ideal for a rarely changing value such as the theme:
Redux Toolkit suits a frequently updated cart that many components read in different ways:
Core Concepts
Head-to-Head
Why Context Re-Renders
When a provider's value changes — including when it is a new object created on every render — React re-renders every component that reads that context. There is no built-in way to subscribe to just one field. For values that change rarely, this does not matter. For a large object updated on every keystroke, it can re-render much of the app. Mitigations include splitting contexts (state and dispatch separately, or by domain), memoizing the value, and keeping fast-changing state local.
useReducer Plus Context
Combining useReducer with Context gives Redux-like actions and reducers without a library, and works well for a feature-sized slice of state — a multi-step form, a wizard, an editor panel. It still lacks selectors, middleware, and DevTools, and tends to grow awkward as more of the app depends on it.
Redux Toolkit
Modern Redux is Redux Toolkit: configureStore with good defaults, createSlice for reducers and actions with Immer-powered "mutating" updates, createAsyncThunk and listener middleware for side effects, and RTK Query for fetching and caching server data. Much of the boilerplate that gave Redux its reputation is gone. See Redux.
Server State Is a Separate Problem
Lists of projects, user profiles, and search results are server state: owned by the backend, cached on the client, and needing loading states, refetching, invalidation, and deduplication. Libraries built for this — TanStack Query or RTK Query — handle it far better than storing responses in Context or hand-written Redux slices. Once server state moves out, the remaining client state is usually small.
Other Options
The Decision Framework
Best Practices
Start Local, Lift When Needed
Keep state in the component that uses it, lift it to a common parent when siblings need it, and reach for Context or a store only when prop passing becomes painful across distant components.
Split Contexts by Change Frequency
Put rarely changing values and fast-changing values in separate providers, so frequent updates do not re-render every consumer.
Select Narrowly
With Redux or Zustand, select the smallest data a component needs and derive values with memoized selectors.
Keep Server State Out of Client Stores
Use a server-state library for API data. Duplicating responses into Redux or Context invites stale data and manual cache invalidation.
Common Mistakes
One Giant Context
Redux for Everything
New Context Values on Every Render
FAQ
Can React Context replace Redux?
For small apps and rarely changing shared values, yes. For complex, frequently updated state used across many components, Context lacks selectors, middleware, and DevTools, so Redux Toolkit or a lighter store is usually a better fit.
Is Redux still relevant?
Yes. Redux Toolkit is a well-maintained, widely used choice for large applications, especially with RTK Query. Many smaller apps no longer need it once server state is handled by a dedicated library.
Why does my whole app re-render when context changes?
Every component that reads a context re-renders when the provider's value changes, and a value object created on each render counts as a change. Split contexts, memoize values, or move fast-changing state to a store with selectors.
Should I use Zustand instead of Redux?
Zustand offers selector-based subscriptions with very little setup and suits many apps well. Redux Toolkit offers stronger conventions, middleware, DevTools, and RTK Query, which help larger teams and complex state.
Where should API data live?
In a server-state library such as TanStack Query or RTK Query, which handles caching, refetching, loading states, and invalidation. Avoid copying API responses into Context or general-purpose stores.
Related Topics
- State Management — Approaches to frontend state
- Redux — Redux Toolkit in depth
- React Context — Context API patterns
- TanStack Query — Server-state management
- React Performance — Avoiding unnecessary re-renders
- React — The component model behind both