useReducer hook in react

Published On:
Read Time: 5 mins

useReducer() hook is a react hook that can be used to manage the complex state of a component. It can even become a good alternative to useState hook in some cases. useReducer simplifies the complex state logic using a reducer function. So let's learn about useReducer hook today!


Syntax

useReducer(reducer, initialArg, init?)

Parameters

  • reducer: The reducer should be a function that updates the state. It takes two arguments state and action, and returns the next state after the calculations based on the provided action. Here, State represents the current state and action represents the operation type that user wants to perform in order to update the current state. Usually, the type of the state can be anything (object, array, string, integer, etc.) but an action is a string for the most of the times but it can also be of any type.

  • initialArg: It is the initial value of the state. It can be of any type.

  • init (optional): This is optional and it is a funtion that should return the initial state just like we have one in useState() hook. If it’s not given, the initial state is set to initialArg or else the initial state is set to the result of calling init(initialArg).

Returns

useReducer() returns two values in an array just like useState(), whereas

  1. The first value is a current state at that particular time. For the first render it’s set to initialArg and to init(initialArg) if the init is given (as explained above).
  2. The second value is a dispatch function that is used to updated the current state. This takes only one argument that an action. Here, an action can be an object that contains the action type and action payload. This function does not have to return any value.

What is reducer?

Well, In react a reducer function is a pure JavaScript function that updates state of a component in response to a certain action. Reducer functions are very popular among state management libraries like for Redux. The main goal of this function is to take the current state and the action and based on the action it performs certain action on that state like Adding, Editing and Removing things and then return the new calculated state. Here is an example of the reducer function.

const initialState = {
  count: 0,
};

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT_BY":
      return { ...state, count: action.payload };
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "DECREMENT":
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
}

Here is a digram to make is more easier to understand

reducer function

Usage

import { useReducer } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "INCREMENT_BY":
      return { ...state, count: state.count + action.payload };
    case "INCREMENT":
      return { ...state, count: state.count + 1 };
    case "DECREMENT":
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
}

export default function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      <h1>Counter: {state.count}</h1>
      <button
        onClick={() => {
          dispatch({ type: "INCREMENT" });
        }}
      >
        Increment Counter
      </button>
      <button
        onClick={() => {
          dispatch({ type: "DECREMENT" });
        }}
      >
        Decrement Counter
      </button>
      <button
        onClick={() => {
          dispatch({ type: "INCREMENT_BY", payload: 5 });
        }}
      >
        Incrment Counter by 5
      </button>
    </>
  );
}

Exaplination

  • At the time of first render we initialize our state to { count: 0 }.
  • Whenever we click on the increment button we dispatch an action INCREMENT.
  • Whenever we dispatch and action the reducer function get called with the state and action arguments, here the state would be { count: 0 } at that moment and action would be { type: "INCREMENT" }.
  • Now, as per action.type the macthed case clause gets excuted, and it returns the new state, that is { count: 1 }.
  • Since state is updated React will now re-render the component and we will see the new counter value being displayed on the screen.
  • Same process happens for the DECREMENT action but in case of INCREMENT_BY action the provided action would be { type: "INCREMENT_BY", payload: 5 } and as per the logic the count will be incrementd by 5.

useState() vs useReducer()

The useReducer() hook in mostly used when we have complex state logic that involves multiple sub-values such as nasted objects or arryas or when the next state purely depends on the previous state. Whereas the useState() is used to store simple state such as strings, integer or boolean values. useReducer() is useful for managing state in components that has more complex state transitions or when we have a large number of state variables that interact with each other. Whenever useState() is a simpler and more concise way to manage state when you only have one or a few independent state variables to keep track of. So,

  • useReducer() when out component's state management is complex, involves derived state, or requires more predictability and control over state transitions.
  • useState() when we have a few independent state variables and data to store is simple in structure that is a integer, string and boolean.

That's all about an arguably underrated useReducer() hook, Hope you enjoyed the reading and learnt a thing or two, stay stuned!

Resources



Built with Nextjs, Tailwindcss and much