DEV Community

Cover image for Deep Dive Into the useReducer() hook
Debajit Mallick
Debajit Mallick

Posted on

Deep Dive Into the useReducer() hook

Introduction

In React, useReducer() is one of the most important hooks. We use the useState() hook for component-based state management. That is good if your component only has two or three states. But if you have many states in the component, then useReducer() can be a better choice.

When to use it?

The initial setup of the useReducer() hook is overwhelming for beginners. But over time, it will make your code more modular and readable. If your code has more than four or five related states, instead of the useState(), use the useReducer() hook.

How to use it?

There are several steps involved in defining the useReducer() hook.

  1. Build a reducer function.
  2. Initialize the useReducer() hook.
  3. Dispatch an event.

1. Build a reducer function:

Firstly, you need to write a reducer function. This function always gets two parameters. The first parameter is the current state, and the second is the action. In this action, we can pass any payload. This action is an object where we always pass a key called type. With this type parameter, we can check different conditions and return values based on it. These values are going to be the new value of the state variable. This reducer functions always needs to be a pure function. That means it will not produce any side effects. Below is an example of a reducer:

function counterReducer(state, action) {
 switch (action.type) {
   case 'INCREMENT': {
     return state + 1;
   }
   case 'DECREMENT': {
     return state - 1;
   }
   default: {
     alert('You entered wrong action type');
     return 0;
   }
 }
}
Enter fullscreen mode Exit fullscreen mode

2. Initialize the useReducer() hook:

In this step, import the useReducer() hook from react. Then, same as the useState(), declare a state. But, in the case of useReducer(), the first value is the state, and the second is a state changer method dispatch. We will discuss the dispatch in the next step. The useReducer() hook takes three parameters:

  • Reducer Function.
  • Initial Argument.
  • Init function.

Reducer Function

It is the same reducer function we talked about earlier. We have to pass that reducer function as the first parameter of the useReducer() hook.

Initial Argument

It is the initial value of the state. If the initial state is small, we declare it inside the useReducer() hook. Otherwise, we store values inside a constant and refer to that inside the useReducer() function.

Init function

It is an optional parameter. It is an initializer function which returns the value of the initial state. If it’s not specified, the initial state is set as the initial argument. Otherwise, the initial state is set to the result of calling init(initialArg).

const [count, dispatch] = useReducer(counterReducer, 0);
Enter fullscreen mode Exit fullscreen mode

3. Dispatch an event

Let’s talk about the dispatch function. It is the second value while declaring the useReducer() hook. In the dispatch, we can pass an object. This object is the action parameter value of the reducer function. We always pass a type key inside the dispatch function. It helps us to check the condition and return the proper value for the state. Below are the two examples of incrementing and decrementing a counter with a dispatch function.

const incrementCount = () => {
   dispatch({
     type: 'INCREMENT',
   });
 };


 const decermentCount = () => {
   dispatch({
     type: 'DECREMENT',
   });
 };

Enter fullscreen mode Exit fullscreen mode

In large projects, we declare the reducer function in a different file and export it from there. As it is a pure function, declaring it outside the component doesn’t affect the state. Below is the complete example code of the counter app.
In the App.js file:

import { useReducer } from 'react';
import { counterReducer } from './reducers';


const App = () => {
 const [count, dispatch] = useReducer(counterReducer, 0);


 const incrementCount = () => {
   dispatch({
     type: 'INCREMENT',
   });
 };


 const decermentCount = () => {
   dispatch({
     type: 'DECREMENT',
   });
 };


 return (
   <div className='container'>
     <h1 className='container-heading'>Counter App</h1>
     <section className='counter-container'>
       <h2 className='counter-value'>{count}</h2>
       <div className='button-container'>
         <button className='btn increment-btn' onClick={incrementCount}>
           +
         </button>
         <button className='btn decrement-btn' onClick={decermentCount}>
           -
         </button>
       </div>
     </section>
   </div>
 );
};


export default App;
Enter fullscreen mode Exit fullscreen mode

In the reducers.js file,

export function counterReducer(state, action) {
 switch (action.type) {
   case 'INCREMENT': {
     return state + 1;
   }
   case 'DECREMENT': {
     return state - 1;
   }
   default: {
     alert('You entered wrong action type');
     return 0;
   }
 }
}
Enter fullscreen mode Exit fullscreen mode

Summary

In this blog, we discussed the useReducer() hook, when to use it, how to declare it and the things you need to keep in mind while using the useReducer() hook. Follow me to learn more about React and other Frontend Development skills.

Top comments (0)