Best Practices7 min read · Updated 2025-06-01

React Context API vs Redux: When to Use Which in 2025

Context API is built in. Redux has devtools and middleware. Understanding when each is the right tool is one of the most common senior React interview questions.

💡 Practice these concepts interactively with AI feedback

Start Practicing →

React Context API vs Redux: When to Use Which

Context API: What It Does Well

Context is React's built-in solution for sharing state without prop drilling. It's a broadcast channel — set a value at the top, consume it anywhere below.

// 1. Create the context
const ThemeContext = createContext('light')

// 2. Provide at the top function App() { const [theme, setTheme] = useState('light') const value = useMemo(() => ({ theme, setTheme }), [theme]) return ( <ThemeContext.Provider value={value}> <Layout /> </ThemeContext.Provider> ) }

// 3. Consume anywhere below — no prop drilling function Button() { const { theme } = useContext(ThemeContext) return <button className={theme}>Click</button> }

Context is ideal for: current user, theme, locale, feature flags — values that change infrequently and are needed across many components.

Context's Limitations

The re-render problem: Every component that calls useContext(MyContext) re-renders when the context value changes — not just the parts of the value they actually use.

// ❌ One big context — a cart change re-renders Avatar and Settings
const AppContext = createContext({ user, cart, theme, setCart, setTheme })

// ✅ Split by domain and update frequency const UserContext = createContext({ user }) // rarely changes const CartContext = createContext({ cart, setCart }) // changes often const ThemeContext = createContext({ theme }) // changes rarely

No middleware: Context has no built-in support for async actions, logging, or side effects. You handle these manually.

No DevTools: No time-travel debugging or action history.

Verdict on Context: Great for 1-3 pieces of global state in small-to-medium apps. Starts hurting when you have many unrelated values that change at different frequencies.

Redux Toolkit: Structured State for Large Apps

Modern Redux uses Redux Toolkit (RTK) — the official, opinionated setup. Gone are the days of hand-written action types and reducers.

import { createSlice, configureStore } from '@reduxjs/toolkit'

const cartSlice = createSlice({ name: 'cart', initialState: { items: [] }, reducers: { addItem: (state, action) => { state.items.push(action.payload) // Immer makes mutations safe }, removeItem: (state, action) => { state.items = state.items.filter(i => i.id !== action.payload) }, }, })

export const { addItem, removeItem } = cartSlice.actions const store = configureStore({ reducer: { cart: cartSlice.reducer } })

// In components:
function Cart() {
  const items = useSelector(state => state.cart.items)
  const dispatch = useDispatch()
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>
          {item.name}
          <button onClick={() => dispatch(removeItem(item.id))}>Remove</button>
        </li>
      ))}
    </ul>
  )
}

What Redux gives you that Context doesn't:

  • Redux DevTools with time-travel debugging and action replays
  • Fine-grained subscriptions via selectors — component only re-renders when its slice changes
  • Middleware for async (Redux Thunk), logging, and analytics
  • Predictable, normalized state structure
  • Works outside React (useful for Web Workers, SSR hydration)

Modern Alternatives

Zustand — minimal API, no boilerplate, subscriptions out of the box:

const useStore = create(set => ({   count: 0,   inc: () => set(s => ({ count: s.count + 1 })), }))

// Component only re-renders when count changes const count = useStore(s => s.count)

Jotai / Recoil — atomic state model. Components subscribe to individual atoms, not a global store. Each atom re-renders only its subscribers.

Decision Matrix

| Situation | Use | |---|---| | 1-3 pieces of global state (theme, user) | Context | | Complex state with many slices | Redux Toolkit or Zustand | | Need DevTools, time-travel debugging | Redux Toolkit | | Small/medium app, minimal boilerplate | Zustand | | Atomic state with isolated subscriptions | Jotai | | Async server data (API responses) | React Query or SWR |

The Interview Answer

"Context is the right choice for simple global state — current user, theme — in small to medium apps. Redux Toolkit is better for large apps with many state slices, teams needing DevTools, or complex async flows. Zustand is a lightweight middle ground with Redux-like subscriptions but without the boilerplate. For server data, I'd use React Query rather than putting API responses into either."

Practice at [JSPrep Pro](/auth).

📚 Practice These Topics
React Context API
8–12 questions

Put This Into Practice

Reading articles is passive. JSPrep Pro makes you actively recall, predict output, and get AI feedback.

Start Free →Browse All Questions

Related Articles

Deep Dive
We Built a RAG-Powered AI Question Engine Into a JavaScript Interview Platform — Here's Exactly How It Works
12 min read
Build Systems
Monorepo with Turborepo vs Nx: The Complete Comparison (2025)
9 min read
Core Concepts
map() vs forEach() in JavaScript: Which One to Use and Why It Matters
7 min read