React useReducer
Published: 2023-05-11 09:33:57

#### Table of content

1. Introduction

2. The useReducer Syntax
 2.1. What is a state in React
 2.2. What is a dispatch in React
 2.3. The Reducer function
 2.4. Initial state
 2.5. Lazy initialization 

3. How the useReducer hook works
4. Bailing out of a dispatch
5. useReducer with Typescript 
6. useState Vs useReducer
7. When to use useReducer 
8. When not to use useReducer 
9. Recommend videos
10. Interesting reads
11. Conclusion 


## Introduction

State management has been a common topic in the development world over the years. It's a challenging part of the development process, especially for huge applications. This challenge has been solved in many different ways over time and keeps evolving in positive ways.

In this article, we're going to learn from grassroots, what there is to know about the `useReducer` hook, how it helps you manage application state better (and logic), along with real-world examples of how it works and why you might want to use it in your next or current project.

## The useReducer Syntax

`const [state, dispatch] = useReducer(reducer, initialArg, init);`

The **useReducer** is a function that takes up to three arguments and returns a **state** and a **dispatch**. These three arguments are used to determine what the **state** is and how the **dispatch** function works.

![useReducer hook by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54jhsxflsn09gjjpdigi.png)
Don't worry about understanding this upfront, we'll go through every inch of what this means and how it works.

### What is a state in React?

`const [state, ...`

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. **State** is a fundamental idea in React.
Here's a visual example of a **state** in React, holding some information about a user.

![States in useReducer by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zrscnrf1yhcd86g822ls.png)


### What is a dispatch in React?

`const [state, dispatch...`

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 😎


![the reducer function by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h5cepjdresrw2cqs1d6n.png)


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**.

### The reducer function

`const [state, dispatch] = useReducer(reducer, ...`

The reducer function is a special handler that takes in two parameters. The application's current `state` and an `action` object, then it 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 what to do by passing it an action 💭?. These actions usually contain a `type` (what to do) and a `payload` (what it needs to do the job).

Here's a typical example of what a reducer function looks like:

```
function reducer(state, action) {
  switch (action.type) {
    case "FIX_BUGS":
      return { totalBugs: state.totalBugs - 1 };
    case "CREATE_BUGS":
      return { totalBugs: state.totalBugs + 1 };
    case "SET_TOTAL_BUGS":
      return { totalBugs: action.payload };
    default:
      throw new Error();
  }
}
```
Now we're starting to connect the dots as we'll go through what all these mean visually.


![the use reducer function by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rw0537lfmsf55ov7aqzj.png)

Let’s delve into what’s happening in the switch statement. 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.

We have three cases in our `switch` statement, which are `case "FIX_BUGS"`, `case "CREATE_BUGS"` and `case "SET_TOTAL_BUGS"`. These are the actions we're explicitly trying to handle. The `default` only fires when we `dispatch` an action that doesn't match any of our cases. See **cases** (or action types) as a store of all possible things a particular reducer can do. If the `reducer` were a person, "cases" would be the skill list on the CV.

Here's a visual representation of how the **dispatch** tells the reducer what to do.


![dispatch actions paired with reducer by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/77mm1gfpcyqp8lyuwjp8.png)

### The initial state

`const [state, dispatch] = useReducer(reducer, initialArg, ...`

The initial state in a react `useReducer` function is the starting state of our application e.g. The default state. In the example we used earlier, we're setting the total bugs of our application in the reducer function based on what type of action the `dispatch` tells us. For this reason, we can set the starting point or default state of our bugs count to say... "0" 🤔? or maybe even "100"? 🐛.

Let's do a hundred! 😎 `{totalBugs : 100}`

### Lazy initialization

`const [state, dispatch] = useReducer(reducer, initialArg, init);`

The `useReducer` takes in an optional third parameter we'll call `init`. This `init` is going to be a function we'll pass as the third argument to `useReducer`. This can be useful if we'd like to create the initial state lazily.

A common use case would be a situation where the initial state needs to go through some calculations to arrive at a default state or has to fetch data from an API, etc. It looks something like this in code: 

```
const init = (initalState) => {
  console.log(initalState); // 100

//... do some code magic 🪄
//...

  return inital;  // return desired state

};
```

## How the useReducer hook works

Now that we've gone through the syntax: `const [state, dispatch] = useReducer(reducer, initialArg, init);` from left to right, it's time to start putting together the pieces in code.

Here's the complete code snippet for our bugs count application.

```
import { useReducer, useState } from "react";

function reducer(state, action) {
  switch (action.type) {
    case "FIX_BUGS":
      return { totalBugs: state.totalBugs - 1 };
    case "CREATE_BUGS":
      return { totalBugs: state.totalBugs + 1 };
    case "SET_TOTAL_BUGS":
      return { totalBugs: action.payload };
    default:
      throw new Error();
  }
}
const init = (inital) => {
  console.log(inital); // 100
  return inital;
};

export default function App() {
  const [state, dispatch] = useReducer(reducer, { totalBugs: 100 }, init);

  // creating a new state so we don't add extra in the reducer state
  // (this is just for examples)
  const [inputState, setInputState] = useState(0);

  return (
    <div className="App">
      <h1>useReducer</h1>
      <p>{state.totalBugs} Bugs Left 🧑‍💻</p>
      <button onClick={() => dispatch({ type: "FIX_BUGS" })}>FIX_BUGS</button>
      <button onClick={() => dispatch({ type: "CREATE_BUGS" })}>
        CREATE_BUGS
      </button>
      <input
        onChange={(e) => setInputState(+e.target.value)}
        value={inputState}
        type="number"
      />
      <button
        onClick={() =>
          dispatch({ type: "SET_TOTAL_BUGS", payload: inputState })
        }
      >
        SET_TOTAL_BUGS
      </button>
    </div>
  );
}
```

For a live preview of the working code. I created a sandbox.

{% embed https://codesandbox.io/embed/usereducer-function-sjh0e8?fontsize=14&hidenavigation=1&theme=dark %}


From the walkthrough of the **useReducer** syntax and what each bolt and knot means, to seeing the actual code in action. We can denote that the `useReducer` is a function that can take up to three arguments and returns a `state` and a `dispatch`.

Here's a simple and summarized visual representation of the `useReducer` lifecycle in code.

![useReducer lifecycle by Lucius emmanuel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zv9q0kllclyw1d00bjcj.png)

## Bailing out of a dispatch

If you return the same `state` in your `reducer` hook as the current `state`. React is smart enough to bail out of rendering or firing effects on components depending on that `state`. This is because React uses the [Object.is comparison algorithm](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description) and this tells React that nothing has changed.

## useReducer with Typescript

`useReducer` is no stranger to us anymore but how do we actually use it with TypeScript 💭?. Now if you're already familiar with TypeScript, this one should be a piece of cake, however, if you're fairly new, don't worry, we'll have a quick and simple example to get us going.

What we're going to do here is by no means a *rule*, you're free to use any formula or paradigm that makes you sleep better at night 😉.

Here it is:

```
import { ChangeEvent, useReducer } from "react";

// for our state
interface State {
  firstName: string;
  lastName: string;
  age: number;
  language: string;
}

// list of all possible types
enum ActionTypes {
  UPDATE = "UPDATE",
  RESET = "RESET"
}

// action type
interface Actions {
  type: ActionTypes;
  payload?: {
    key: string;
    value: string;
  };
}

// if we need to do some work to provide initial state
const init = (inital: State) => {
  console.log(inital);
  return inital;
};

// the default state of our app
const initialState = {
  firstName: "",
  lastName: "",
  age: 0,
  language: ""
};

// the reducer handler function
const userFormReducer = (state: State, action: Actions) => {
  switch (action.type) {
    case "UPDATE":
      return { ...state, [action.payload.key]: action.payload.value };
    case "RESET":
      return initialState;
    default:
      throw new Error();
  }
};

export const UserForm = () => {
  const [state, dispatch] = useReducer(userFormReducer, initialState, init);

  // for input change event
  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
    dispatch({
      type: ActionTypes.UPDATE,
      payload: { key: event.target.name, value: event.target.value }
    });
  };

  return (
    <div>
      <h1>TypeScript Example</h1>
      <input
        value={state.firstName}
        type="text"
        name="firstName"
        onChange={handleChange}
        placeholder="first name"
      />
      <input
        value={state.lastName}
        type="text"
        name="lastName"
        onChange={handleChange}
        placeholder="lastName"
      />
      <input
        value={state.language}
        type="text"
        name="language"
        onChange={handleChange}
        placeholder="language"
      />
      <input
        value={state.age}
        type="text"
        name="age"
        onChange={handleChange}
        placeholder=""
      />
      <button
        onClick={() => dispatch({ type: ActionTypes.RESET })}
        type="reset"
      >
        RESET
      </button>
    </div>
  );
};

```

To test this out yourself, live on Sandbox. I've also included the typescript example.

{% embed https://codesandbox.io/embed/usereducer-function-sjh0e8?fontsize=14&hidenavigation=1&theme=dark %}

This article is not about TypeScript, so we won't be explaining what's going on in that code. A few things to note however is that I intentionally put all the TypeScript code in one file. In a real-world application, you'd most certainly create files for different things and your approach might be quite different (Again, whatever helps you sleep better at night 😉).

## useState Vs useReducer

```
const [state, dispatch] = useReducer(reducer, initialArg, init);
//vs
const [state, setState] = useState(initialState)
```
We won't be creating a webinar or zoom meeting to argue about this, but a rule of thumb is, that everything you can do with a `useReducer` you can do with a `useState`. In fact, the `useReducer` hook is just an alternative to `useState` with a few clear differences such as:

* Readability
* Ease of use and,
* Syntax

> Note 💡
React guarantees that `dispatch` function identity is stable and won’t change on "re-renders". This is why it’s safe to omit from the `useEffect` or `useCallback` hook dependency list.

## When to use the useReducer hook

use a `useReducer` hook over `useState` when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. This is fairly common when your application begins to grow in size. `useReducer` also lets you improve performance for components that trigger deep updates because you can [pass down a dispatch](https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down) instead of callbacks.

## When not to use useReducer

`useReducer` is awesome, but there are certain scenarios where it doesn't make our lives any easier. Here are a few of such cases:

* Don't use a `useReducer` hook when you're dealing with simple state logic.
* When your application needs a single source of truth. You'll be better off using a more powerful library like [Redux](https://react-redux.js.org/)
* When prop-drilling starts to yell at you. This happens when you get trapped in the hellish world of passing down too many props (state) to and from child components to a child component that later comes to hunt you.
* When state lifting to parent/top-level components no longer suffices.

## Recommend videos
There's always more to learn, so if you'd like to learn more tricks and hacks about the useReducer hook. I'd recommend you look up the video links below

* [React Hooks useReducer Tutorial](https://www.youtube.com/watch?v=wcRawY6aJaw)
* [useReducer with TypeScript](https://www.youtube.com/watch?v=9KzQ9xFSAEU)

## More interesting reads from my blogs

* [How To Create A Global "JSON Search Algorithm" In JavaScript](https://dev.to/emmaccen/how-to-create-a-global-json-search-algorithm-in-javascript-55ko)
* [How To Know If An Element Is Visible In Viewport](https://dev.to/emmaccen/how-to-know-if-an-element-is-visible-in-viewport-c45)
* [How To Create A "Glassmorphic" Template In Pure HTML & CSS](https://dev.to/emmaccen/how-to-create-a-glassmorphic-template-in-pure-html-css-3jo4)

## Conclusion

The useReducer is a powerful hook if used properly and I hope we've been able to learn about it without any confusion. If you'd like to contribute to this post or drop feedback, feel free to leave a comment 📝 and drop a like ❣️. Thanks for reading, you're awesome! 😎

Happy Coding!

I'd love to connect with you 🙂

* [LinkedIn](https://www.linkedin.com/in/emmanuel-lucius-emmaccen/)
* [GitHub](https://github.com/Emmaccen)

PS: This article was initially published on "Copycat"