Ronaiza Cardoso

13 Julho 2026

Min Read

React Hooks vs Redux: When to Use Each

React hooks vs Redux is a scope question, not a quality one. Use React hooks for state that lives inside a component, plus small shared values like theme or locale. Reach for Redux when several unrelated features lean on the same data, when more than five engineers touch the codebase, or when you need a traceable record of every change. Most production apps end up using both, at different layers.

Think of state as water in a building. Hooks are the taps in each room, close to where the water gets used. Redux is the mains supply, the pressure valves and the meter that tells you exactly who ran the bath at 3am.

Same substance. Very different jobs. That is the whole argument, and everything below is the working.

What does a bad state decision actually cost you?

State architecture is one of the few frontend choices that compounds. Pick too little structure and you pay in onboarding time and bugs nobody can reproduce. Pick too much and you pay in boilerplate nobody asked for.

The asymmetry is the interesting part. Over-engineering costs you a few wasted weeks, and you feel it immediately. Under-engineering costs you quarters of quiet velocity decay, and you only feel it once your team has grown past the point where a rewrite is cheap.

So this is a CTO question dressed up as a developer preference. We have framed every technical section below with the delivery risk attached, because that is the bit that shows up in your roadmap.

blue arrow to the left
Imaginary Cloud logo

What are React hooks?

React hooks are how you handle state and lifecycle inside function components, without classes. They landed in React 16.8, built to cut component complexity by making logic shareable.

The real payoff is custom hooks. Pull out behaviour you use in more than one place, and stop writing it twice.

// useDebouncedValue.js
import { useEffect, useState } from 'react';

export function useDebouncedValue(value, delay = 300) {
  const [debounced, setDebounced] = useState(value);

  useEffect(() => {
    const timer = setTimeout(() => setDebounced(value), delay);
    return () => clearTimeout(timer);
  }, [value, delay]);

  return debounced;
}

The catch: hooks impose no conventions at all. Where shared state lives becomes a judgement call each engineer makes alone, and nothing in the tooling writes it down. Free at two engineers. Expensive at ten.

blue arrow to the left
Imaginary Cloud logo

What is Redux?

Redux is a library for managing global application state. One store, a disciplined way to change it, and tooling that watches every change as it happens.

The official documentation gives three principles:

  1. Single source of truth. Global state lives in one object tree, inside one store.
  2. State is read-only. The only way to change it is by dispatching an action.
  3. Changes are made with pure functions. Reducers describe how state transforms, and nothing else.

Redux also ships its own hooks, useSelector and useDispatch, so function components can read from the store without any class-based wiring. (This is the react redux binding, and yes, you need it: more on that in the FAQ.)

What the ceremony buys you:

  • Selector-based subscriptions. A component subscribes to the slice of state it actually uses. Change the basket, and the notification feed sits perfectly still.
  • Redux DevTools. Time-travel debugging and a readable log of every action. In practice that is the difference between diagnosing a production incident in an hour and spending a day reconstructing state by reading code.
  • A serialisable snapshot of the whole application state, at any moment you like.

The cost: setup time, boilerplate, and a learning curve for anyone new to it. Redux Toolkit trims all three considerably, and it is the officially recommended way to write Redux today.

blue arrow to the left
Imaginary Cloud logo

What is Redux?

Redux is a library for managing the global application state. In this library, we can find several tools that help us, developers, to be in touch with the state of the application and also transform it by giving the user the ability to emit actions.

Redux, as the documentation says, can be described in three fundamental principles:

  1. Single source of truth: the global state of your application is stored in an object tree within a single undefined.‍
  2. The State is read-only: The only way to change the undefined is by emitting actions.‍
  3. Changes are made with pure functions: To update the undefined, the reducer should be written as a pure function.‍

Redux even updated the library with its custom hooks. These can be used to integrate the components that use the React Hooks features to access data from the store and dispatch actions without relying on the components classes.

Now that we are a little more familiar with Redux and React Hooks let's see the difference between them.

blue arrow to the left
Imaginary Cloud logo

What does the jargon actually mean?

Most articles on this topic assume you already speak the language. That assumption is precisely why the topic stays murky, so here is the vocabulary in plain words.

State is any data that changes over time and affects what your user sees. A form input. A logged-in user. A basket.

A reducer is a function that takes the current state and an action, then returns a new state without touching the original. It turns every change into something explicit and traceable.

A pure function always gives the same output for the same input and changes nothing outside itself. No network calls, no writing to variables elsewhere. Reducers have to be pure, because that is what makes state changes reproducible and testable.

Emitting (or dispatching) an action means describing a change as a plain object rather than just doing it. You do not mutate the basket. You dispatch { type: 'basket/itemAdded', payload: item } and let the reducer work out the result.

Provider and consumer are the two halves of React's Context API. The provider holds a value and offers it to everything below it in the tree. The consumer is any component that reads it.

A selector is a small function that plucks one slice out of the store, like state => state.basket.total. Selector-based subscription means a component re-renders only when its slice moves.

Blast radius is the set of components a single state change forces to re-render. Small is good.

A thunk is a function you dispatch instead of a plain action, so you can run asynchronous work (an API call, usually) before dispatching the real thing.

RTK Query is the data-fetching and caching layer bundled with Redux Toolkit. It handles server data, so that data never has to squat in your store by hand.

blue arrow to the left
Imaginary Cloud logo

Why does the Context API break down at scale?

Context was built for values that barely move. It has no selector mechanism whatsoever. So when a provider's value changes, every consumer beneath it re-renders, including the components that never touched the bit that changed.

Back to the plumbing. Context is one big pipe feeding the whole building. Turn a tap on the third floor and every room in the block shudders.

For a theme toggle, who cares. For a context holding the current user, an open basket, a live notification feed and a filter panel, it is a cliff edge. One keystroke in the filter input re-renders the notification list.

Teams usually find this out three months before launch, once the workarounds have quietly piled up. And the workarounds are the actual cost: splitting one context into six, memoising provider values, wrapping consumers in React.memo, reshaping the tree to shrink the blast radius.

Each one is defensible on its own. Together they are a bespoke, undocumented state manager that exactly one engineer understands, and it costs more to maintain than the library it was adopted to avoid. That is a well-worn road to technical debt.

Redux sidesteps this by design. Selectors mean the blast radius is defined by what a component actually reads.

Banner graphic for Imaginary Cloud services. Text reads: "Build scalable products with Web & Mobile Development. We help you shape digital products from scratch or improve your existing ones." Includes a "LEARN MORE" button and isometric digital device illustration.
blue arrow to the left
Imaginary Cloud logo

useReducer belongs in components carrying complex internal logic. A multi-step form. A wizard. A data grid juggling sorting, filtering and pagination. Where useState leaves you with five interdependent setters, one reducer gives you a single coherent transition function.

const initialState = { status: 'idle', items: [], error: null };

function feedReducer(state, action) {
  switch (action.type) {
    case 'FETCH_STARTED':
      return { ...state, status: 'loading', error: null };
    case 'FETCH_SUCCEEDED':
      return { status: 'ready', items: action.payload, error: null };
    case 'FETCH_FAILED':
      return { ...state, status: 'error', error: action.payload };
    default:
      return state;
  }
}

const [state, dispatch] = useReducer(feedReducer, initialState);

It takes the reducer and the initial state, and hands back the current state plus a dispatch function. Never write to state directly. Dispatch an action, always shaped as an object with a type (what happened) and a payload (the data the change needs).

So can useReducer replace Redux? At component level the question never really arises, because it is simply the right tool.

Promote it to global state through context, though, and you get most of Redux's shape with none of its infrastructure. You will find yourself rebuilding selector-based subscriptions, middleware for async work, and debugging tooling. From scratch. On a Tuesday, in the middle of a sprint that was meant to be about the product.

That rebuild is not free, and it is on nobody's roadmap. The dividing line is scope, not complexity.

blue arrow to the left
Imaginary Cloud logo

React hooks vs Redux vs Zustand: the real 2026 decision

Truth be told, for most new projects the honest comparison is no longer a straight two-way fight. Zustand has become the default challenger, and pretending otherwise gives you a false choice.

Zustand is a minimal store. You create some state, you consume it through a hook. No provider, barely any boilerplate, and, crucially, selector-based subscriptions straight out of the box, which is the one thing plain context cannot give you.

According to the State of React 2025 survey, Redux and Redux Toolkit remain the most widespread state management solutions, but Zustand is gaining ground fast and leads the category on user satisfaction, enough that the survey authors call it the category leader. The same survey notes that a large share of respondents use no state management library at all, because useState and useContext do the job perfectly well for what they are building.

Read as a decision, not a trend:

  • Hooks only. Fastest time-to-value. Right until shared state crosses three or four concerns.
  • Zustand. Solves the context re-render problem with almost no onboarding cost. The pragmatic pick for small and mid-sized teams who have outgrown context but do not need an audit trail.
  • Redux Toolkit. Right when structure itself is the deliverable. Large teams, regulated domains, anywhere state changes must be traceable for compliance.

One caveat, and it is the big one. Much of what teams reach for a store to solve is server state, meaning cached API responses. That belongs in TanStack Query or SWR, not in any client store. Sort that first and more often than not the remaining decision gets a lot easier.

blue arrow to the left
Imaginary Cloud logo

The Imaginary Cloud State Matrix

Most comparisons shrug and say "it depends". Here is what we actually use when we audit or start a React codebase. Two axes: application complexity, meaning how many features share the same data, and team size, meaning how many engineers change that data.

Matrix by Imaginary Cloud mapping React Hooks, Zustand, and Redux Toolkit by project complexity and team size.

The same four rules, in prose, because images travel badly:

  1. One to four engineers, few features sharing data: use React hooks alone. A state library here is over-engineering, and you pay for it in wasted setup.
  2. Five or more engineers, simple application: keep hooks, but write down where shared state lives. Your risk is convention drift, not performance.
  3. Small team, many features sharing data: use Zustand. You need selector-based subscriptions, not organisational scaffolding.
  4. Five or more engineers, many features sharing data: use Redux Toolkit. Structure, audit trail and onboarding speed are worth every line of boilerplate.

And here is the bit that surprises people. Team size, not application complexity, is the stronger predictor. A genuinely complex app maintained by two engineers who share a mental model runs beautifully on hooks. A merely fiddly app maintained by nine engineers across three squads does not, and not because the code cannot express it. Because nine people cannot hold an undocumented convention in their heads at the same time.

What happens when you scale from two engineers to ten?

Picture a product growing from two engineers to ten across a couple of quarters.

At two, hooks-only is optimal. Shared state sits in three contexts, the conventions are unwritten because both engineers wrote them, and shipping is quick. Redux would be dead weight.

At ten, that same architecture flips on you. Onboarding stretches from days into weeks, because there is no canonical answer to "where does this data live", only precedent.

Two engineers solve the same re-render problem independently, in incompatible ways.

Debugging a production incident means reconstructing state by reading code, because there is no action log. Velocity drops, and no single decision caused it.

So the trade-off is not boilerplate versus elegance. It is cost paid upfront versus cost paid at scale, with interest.

The failure runs both ways, mind. Adopting Redux for a two-engineer MVP is a real cost with no return. The signal to watch is not lines of code. It is the day your team stops being able to answer "why did this re-render" without opening a debugger.

blue arrow to the left
Imaginary Cloud logo

How do you migrate from Redux to hooks (or Zustand)?

The reverse migration is increasingly common, usually when the Redux store turns out to be mostly cached server data wearing a disguise.

  1. Audit what the store really holds. In most codebases we inherit, the bulk of it is server state: API responses, cached lists, pagination cursors. That is not client state, and Redux was never its right home.
  2. Move server state to a query library. TanStack Query or SWR handle caching, revalidation and background refetching. The store shrinks dramatically.
  3. Assess what is left. Auth, theme, feature flags, a handful of UI concerns. Frequently small enough for context plus useReducer, or one Zustand store.
  4. Migrate slice by slice. Redux and React hooks coexist quite happily. There is no big-bang cutover, and there should not be one.

Teams regularly find step 2 settles the whole argument on its own. The problem was never Redux. It was using a client state manager as a network cache.

React hooks vs Redux vs Zustand: summary comparison

FeatureReact hooks (Context + useReducer)ZustandRedux (Redux Toolkit)
State scopeComponent-local, or narrow shared slicesGlobal, lightweight storeGlobal, single source of truth
ToolingReact DevTools, no action historyWorks with Redux DevTools via middlewareRedux DevTools, time-travel, full action log
BoilerplateMinimalMinimalModerate, much reduced by Redux Toolkit
Re-render controlManual: memoisation, context splittingBuilt in, via selectorsBuilt in, via selectors
Async handlingRoll your own, or add a query libraryAdd a query libraryThunks, middleware, RTK Query
Onboarding costLow if conventions are documented, high if notLowHigher upfront, lower per extra engineer
Ideal team size1 to 4 engineers1 to 8 engineers5+ engineers, or regulated domains
Ideal applicationMVPs, marketing sites, focused productsMid-sized products with shared UI stateMulti-feature platforms, auditable domains

Want the wider picture? Our guide to React state management covers the full landscape, and our pieces on selecting a tech stack and asynchronous JavaScript patterns cover the ground either side of it.

blue arrow to the left
Imaginary Cloud logo

Frequently asked questions

What does Redux mean?

Redux is an open-source library for managing global application state in JavaScript apps, most often React ones. It keeps shared state in a single object called the store, and changes it only through dispatched actions handled by pure functions called reducers. The name gives the game away: state changes are reduced into one predictable flow.

Should I use Redux or React hooks?

Use hooks for local component state and small shared values like theme or locale. Reach for Redux when several features depend on the same data, when more than five engineers work on the codebase, or when you need an audit trail of state changes. In most production applications, the answer is both, at different layers.

React hooks vs Redux vs Zustand: which should I choose?

Start with hooks. Move to Zustand when shared state outgrows context and you begin fighting re-renders. Move to Redux Toolkit when the team passes roughly five engineers, or the domain demands traceable state changes. Zustand now leads the category on developer satisfaction, while Redux remains the most widely deployed.

Is Redux still relevant in 2026?

Yes. Just not as the automatic default. The State of React 2025 survey finds Redux and Redux Toolkit are still the most widespread solutions, and they remain the strongest option for large teams and regulated domains. For a new project with a small team, Zustand, or no library at all, is now the more common starting point.

When should I use useReducer instead of Redux?

Use useReducer when complex state is penned inside one component or a tight cluster: a multi-step form, a wizard, a data grid. Use Redux when that state is shared across unrelated parts of the application. Scope, not complexity, draws the line.

Can React hooks replace Redux entirely?

For small and mid-sized applications, yes. useContext and useReducer together reproduce most of what Redux does. What they cannot replace without serious custom work is selector-based re-render control, middleware for async logic, and the DevTools debugging experience. Which is exactly what large teams lean on.

What is react redux, and how is it different from Redux?

Redux is framework-agnostic, a state container that works with any UI layer. react-redux is the official binding that wires it into React, giving you the useSelector and useDispatch hooks. You need both to use Redux in a React application.

Does the Context API cause performance problems?

It can. Context has no selector mechanism, so when a provider's value changes, every consumer beneath it re-renders, including the ones that never used the changed part. Fine for values that rarely move. Painful for anything that changes often or is consumed widely.

The verdict: both, deliberately

So is Redux finished? No, of course not. React hooks and Redux are complements, not rivals. Hooks handle component state and shareable logic, Redux handles global state, dispatched actions and the observability that large teams live on, and Zustand now sits comfortably between them.

Back to the building one last time. You do not choose between the tap and the mains. You work out how many rooms need water, how many people are turning the taps, and you plumb accordingly.

Where does your application sit on the complexity axis, where does your team sit on the size axis, and where will both of them sit in twelve months? Architect for that. Not for today.

If you are building or scaling a React application and want a straight answer on your state architecture before it sets hard, our team runs technical audits that do exactly that.

Ronaiza Cardoso
Ronaiza Cardoso

Javascript developer since 2016, I've built mobile apps using Ionic and React Native. Guitar player and cooking lover.

Read more posts by this author

People who read this post, also found these interesting:

Dropdown caret icon