useReducer is a React Hook that provides an alternative to useState for managing complex state logic. It's particularly useful when state transitions depend on the previous state or involve multiple sub-states.

const [state, dispatch] = useReducer(reducer, initialState);
  • reducer: A function that takes the current state and an action, then returns the new state. Based on the action.type, it returns the new state.
  • initialState: The initial value of the state.
  • state: holds the current state value
  • dispatch: A function used to send actions to the reducer.
const initialState = {count : 0};

function reducer(state, action) {
   switch (action.type) {
      case "increment":
         // Return a NEW object with the updated property
         return { ...state, count: state.count + action.payload };
      case "decrement":
         return { ...state, count: state.count - action.payload };

      // ❌ ❌ BAD: Returns a number, not the state object shape! AVOID
      // case "increment":
      //   return state.count + action.payload;

      default:
         throw new Error("Unknown action type");
   }
}
function Component(){
   const [state, dispatch] = useReducer(reducer, initialState);

   const incrementCount = function(){
   //sends an action to the reducer, updating the state accordingly.
      dispatch({ type: "increment", payload: 1 }) 
   }
   const decrementCount = function(){
   //sends an action to the reducer, updating the state accordingly
      dispatch({ type: "decrement", payload: 1 })
   }

   return (
      <button onClick={incrementCount}>+button>
      <span>Count: {state.count}span>
      <button onClick={decrementCount}>-button>
   )
}

📌The reducer must be pure function and return a completely new state object.


How useReducer Works: The Flow

Here’s the step-by-step process detailing how the components of useReducer interact:

  1. Initial Setup: When your component first renders, useReducer is called with your Reducer Function and the initialState. It returns the current State Object (which is the initialState at first) and the Dispatch Function.

  2. Event Trigger: Something happens in your application that requires a state change (e.g., a user clicks a button, types in a field, data arrives).

  3. Dispatching an Action: The event handler for that event calls the Dispatch Function. You pass an Action Object to dispatch. This Action Object contains information about what change needs to happen (the type) and any data needed for that change (the payload).

    • Example: dispatch({ type: 'INCREMENT', payload: 1 })
  4. Reducer Called: React takes the Action Object you dispatched and calls your Reducer Function. It provides two arguments to your reducer:

    • The current State Object.
    • The Action Object you just dispatched.
    • Example: reducer(currentState, { type: 'INCREMENT', payload: 1 })
  5. Calculating the New State: Inside your Reducer Function, you use the action.type (and action.payload if necessary) to determine how to compute the next state based on the current state. This is typically done using a switch statement or if/else conditions based on action.type. Crucially, the reducer must be pure and return a completely new state object (immutability), not modify the existing one.

    • Example: Based on { type: 'INCREMENT', payload: 1 }, the reducer might return { ...currentState, count: currentState.count + 1 }.
  6. State Update: useReducer receives the new state object returned by your Reducer Function. It then updates the internal state associated with your component.

  7. Re-render: React detects that the state managed by useReducer has changed. It schedules your component (and potentially its children) to re-render. When the component re-renders, the useReducer hook will now return the updated State Object from step 6. Your UI then displays the information based on this new state.

So, useReducer provides a structured cycle: an action is dispatched describing an intended change -> the reducer function calculates the new state based on the current state and the action -> React updates the state -> the component re-renders with the new state. The dispatch function is the trigger that kicks off this cycle.


When to use useReducer

  • When state transitions are more complex (if-else chains or multiple related state updates).
  • When you need centralized state management.
  • You have multiple related state variables.
  • State updates are interdependent.
  • When the next state depends on the previous state.
  • You want to keep your components cleaner and more readable.

Why use useReducer

While useState is sufficient for managing simple state, it can become cumbersome when:

  • The component has multiple state variables.
  • State updates are scattered across multiple event handlers.
  • Multiple state updates need to occur simultaneously in response to an event.
  • State updates depend on other state variables. In these cases, useReducer helps organize state updates in a more structured manner.

🧭 When to Use What?

Use Case Recommended Approach
Simple local state (e.g. form inputs, toggles) useState
Complex local state (e.g. nested updates, dependencies) useReducer
Shared global state in a small to medium app useReducer + Context API
Global state in a large, complex application Redux

✅ Conclusion

The useReducer hook is a robust alternative to useState, particularly well-suited for managing complex state logic and scenarios where the next state depends on the previous one. By centralizing state transitions within a pure reducer function, useReducer promotes cleaner, more maintainable code and improves the predictability of state changes.

It's an excellent choice when:

  • You have multiple related pieces of state.
  • State updates are interdependent or complex.
  • You want to separate state logic from UI logic for better readability.

Understanding useReducer not only helps structure state management more effectively within components, but also lays a strong foundation for working with more advanced tools like Redux.


Likes, Comments and feedback are welcome!😅

Happy coding!