Effortlessly Master React State Management with the useReducer Hook

Effortlessly Master React State Management with the useReducer Hook

As a React developer, the managing state can be a daunting task - but not any longer! With the useReducer Hook, effortlessly master React state management in no time. Going beyond traditional setState methods, the useReducer Hook offers a dynamic and versatile approach to state management that elevates the user experience and streamlines the development process. Let's explore the immense power of using the useReducer Hook and its ability to master React state management effortlessly.

One of the main benefits of using useReducer over useState is that it allows for more complex state management logic, such as handling asynchronous actions, and it also makes it easier to test your state updates.

Before proceeding to explain what is useReducer and how to use it, let's get familiar with its syntax of it:

const [state, dispatch] = useReducer(reducer, { count: 0 })

The React useReducer is a pure function that takes up to three arguments and returns a state and a dispatch.

A state in react is a piece of data that represents the current status of our application. This state can be used to provide information on the screen or perform background computations/calculations that allow our application to function. The state is a fundamental idea in React.

Dispatch in React is simply a function that takes an instruction about what to do, then passes that instruction to the reducer as an “action”. In simple terms, see dispatch as a friendly boss that likes to tell the reducer what to do and is happy about it. If you’re familiar with Redux, this term dispatch might not be new to you but, we’ll go through this article assuming you’re new to both Redux and useReducer. First, reducer function.

The reducer function is a special handler that takes in two parameters. The reducer function takes in the application’s current state object and an action object. Then reducer function uses that to determine/compute the next state of our application (it returns a new state).

Remember how we talked about the dispatch telling the reducer function what to do by passing it an action? These actions for the reducer function usually contain a type (what to do) and a payload (what it needs to do the job).



With one simple example, let's better understand how useReducer work. In a real-world application, you’d most likely have more complex logic in the switch but for this example, we’ll be keeping it simple.

function counterReducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    case "reset":
      return { count: 0 };
    default:
      throw new Error();
  }
}
  1. first, we define a counterReducer function that takes the current state and an action and returns the next state.

  2. Inside the reducer function, we use a switch statement to determine which action is being performed and update the state accordingly. In this example, we have three actions: increment, decrement and reset.

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

  const increment = () => {
    dispatch({ type: "increment" });
  };

  const decrement = () => {
    dispatch({ type: "decrement" });
  };

  const reset = () => {
    dispatch({ type: "reset" });
  };

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
      <button onClick={reset}>Reset</button>
    </div>
  );
}
  1. Next, we have the Counter component, which uses the useReducer hook to provide the counterReducer function and an initial state of { count : 0 } to the component.

  2. Inside the component, we render a <p> element to show the current count, and three buttons, one for each action.

  3. Finally, we use the dispatch function to send the appropriate action to the reducer when clicking each button.

Note that, we are passing the initial state to useReducer function, so it will be used to initialize the state only the first time the component is rendered, after that the state will be passed on to the reducer based on the actions and the new state is returned from it.

In summary, useReducer is a critical tool for managing complex states in React because it allows you to centralize state updates and logic in a reducer function. This allows for a more predictable and testable method of dealing with state changes, making your code more maintainable and scalable. By combining useReducer with other hooks such as useContext, you can keep your state centralized, making your component simpler and easier to understand.


Check out the following blogs before reading the upcoming one on the shopping cart with useReducer and useContext:

  1. "The useContext Hook: A Beginner's Guide to Share State in React"

  2. "Fetching data from API with loading state in React"

  3. "Higher Order Components in React"