useState vs useReducer: How to Choose

useState is for simple independent values; useReducer moves related update logic into one function. Learn how to pick between them.

5 min read

useState and useReducer are two ways to hold state in a React component, and they are interchangeable. useState is simpler for one independent value, while useReducer moves related update logic into a single reducer function. The deciding factor is how many updates depend on each other.

The core difference

useState spreads update logic across event handlers. useReducer pulls that logic out of the component into one pure function that decides every next state.

FactoruseStateuseReducer
Code sizeLess upfrontMore boilerplate, less when many handlers repeat
ReadabilityClear for simple valuesClearer for many related transitions
DebuggingHarder to trace which call changed stateOne place to log every action
TestingUsually tested through the componentReducer can be tested in isolation

Neither is faster than the other. Both sit on the same state system, so the choice is about structure, not performance.

When useState is enough

A single counter that only increments is a clear useState case. The update logic is one line, so a reducer would add ceremony without benefit.

App.jsxApp.jsx
import { useState } from "react";
 
export default function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}

Clicking the button increases count by one. There is one value, one handler, and no dependency between separate pieces of state. Two values that update independently also fit useState, as long as neither update reads the other.

When useReducer earns its keep

A form with several fields that reset together shows the reducer advantage. Resetting all fields is one action, not several setter calls.

App.jsxApp.jsx
import { useReducer } from "react";
const initial = { name: "", email: "" };
 
function reducer(state, action) {
  switch (action.type) {
    case "changed": return { ...state, [action.field]: action.value };
    case "reset": return initial;
    default: return state;
  }
}

The changed action updates one field without losing the others, and reset restores the whole object in one branch. If you kept both fields in useState, reset would need two setters and the handlers would drift apart.

How to choose

  • Use useState when one value changes independently and the logic is short.
  • Use useReducer when several fields move together, like a form or a wizard.
  • Use useReducer when many handlers update the same state in similar ways.
  • Switch to useReducer when you keep introducing bugs from scattered update logic.

Debugging and testing

Debugging is where the reducer earns its keep. With useState, a wrong value can come from any handler. With useReducer, you can log every action in the reducer and see exactly which event produced the wrong state.

Because the reducer is pure, you can export it and test it without rendering the component.

A common false equivalence

useState and useReducer are not two different categories of state. useReducer is built on the same mechanism, so it is not more powerful or more correct by itself. Read how to write actions and reducers to learn the reducer side, and see useReducer explained with examples for the full workflow.

Rune AI

Rune AI

Key Insights

  • useState fits simple independent values.
  • useReducer collects related update logic into one pure function.
  • Reducers help with debugging and testing.
  • The two Hooks are equivalent and can be converted.
  • Start with useState and upgrade when updates tangle.
RunePowered by Rune AI

Frequently Asked Questions

Can I use useState and useReducer in the same component?

Yes. They are independent state containers, so you can hold simple values with useState and complex transitions with useReducer in one component.

Are useState and useReducer equivalent?

Yes. useReducer is built on the same state mechanism as useState, and you can convert most components between the two forms.

Does useReducer make my component faster?

No. useReducer does not add performance. It reorganizes update logic, which mainly helps readability, debugging, and testing.

Conclusion

useState is the default for one independent value, and useReducer is the upgrade when several values move together or update logic becomes hard to trace. Start with useState and switch only when the update code gets tangled.