Demystifying React Hooks: useReducer
Tags: javascript, react, beginners, webdev
Published: 2020-07-13 14:54:35

React Hooks are a simpler way to encapsulate stateful behavior and side effects in functional components instead of classes. Some hooks are easier to understand than others, therefore this series of posts will focus on demystifying the hooks that are not as straightforward. 

So far, we have explored useCallback, useMemo, useRef, and useContext so make sure to checkout my previous posts if you haven’t already. This week, let’s start with the basics by explaining the JavaScript ***reduce*** method. Once we explore the basics, it will be much easier to understand the ***useReducer*** hook, as well as how and when to use it in your code.

## What is a reducer?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fdm463l6v56wptuga0o0.png)

A ***reducer*** is the action that will be executed in order to get **only one value.** The goal of a ***reducer*** is to reduce (...duh!). The value returned could be a number, a string, an array or even an object, as long as it is a singular value. Moreover, it is important to highlight that ***reducers*** return a new value instead of mutating your initial value.

***reduces*** are very useful when you want to obtain a single value after applying some logic to a group of values. For instance, if you want to add up an array of numbers to obtain a total value as we do in the following example. 

We apply the JavaScript ***reduce*** method to an array of numbers called `nums = [1,2,3,4,5]`. The `reduce` method takes two parameters: 

**reducer** - a function that provides instructions to obtain one value. In this case, to sum up all the given values in the `nums` array.

```javascript
const reducer = (accumulator, currentValue) => accumulator + currentValue;
```

 **initialValue** - the starting point value when implementing the `reducer` function's instructions. In our example, we define our initial value as 0 so the total value returned reflects only the sum of the values in the array `nums`.

```javascript
const initialValue = 0;
```

Now that we defined the elements involved, let’s see it all together. The `reduce` method takes our `initialValue` and builds on it by following the instructions given under the `reducer` function, adding each value in the `nums` array until it is able to return one total value.

```javascript
// reducer method - the action that will be executed in order to get one value
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// array of values that we want to add up
const nums = [1,2,3,4,5];

// initial value set to 0
const initialValue = 0;

// JavaScript reduce method receives two parameters: the reducer function and initial value defined above
const totalValue = nums.reduce(reducer, initialValue);
```

## What is useReducer()?

The ***useReducer*** hook is used with state management. It receives the following parameters: 

**reducer** - a function that provides instructions on how to manage state. It takes two parameters `state` and `action` and it returns a new state.

```javascript
// reducer type
(state, action) => newState
```

**initialState** - the starting point value. It will change according to the `reducer` instructions.

Does it look familiar? Well yeah... It takes similar parameters as the ***reduce*** function explained above. However, the ***useReducer*** hook does not return just one value as ***reduce*** does. Instead it returns two elements as an array, the current `state` and a `dispatch` function.

```javascript
const [state, dispatch] = useReducer(reducer, initialState);
```

If you are familiar with React hooks, you probably have used ***useState*** before. Let’s compare these two hooks

```javascript
// useState implementation
const [state, setState] = useState(initialState);

// useReducer implementation
const [state, dispatch] = useReducer(reducer, initialState);
```

***useReducer*** and ***useState*** both return a stateful value (`state`), and a function to update the state (`setState` and `dispatch`). In addition, both hooks receive an initial state value (`initialValue`). The main difference in these two initializations is that ***useReducer*** also takes a `reducer` function, which will be called when we use the returned `dispatch` function. Let’s explore how ***useReducer*** works in the next section.

## How to use useReducer?

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vy5bq1x9f26yteauzh97.png)

Sometimes the best way to explain how something works is with an example so let’s take a look at one. Here is a definition for an `initialState`, also called a store of data,  that contains a list of dogs up for adoption with their name, breed, and adoption status.

```javascript
const initialState = [
 {
      name: "Waffles",
      breed: "Chihuahua",
      adopted: false,
  },
  {
      name: "Charlie",
      breed: "Pitbull",
      adopted: true,
  },
  {
      name: "Prince",
      breed: "German Shepherd",
      adopted: false,
  },
];
```

Now let’s create a `reducer` function to update our `initialState` list of dogs as they get adopted or returned. This function takes the following parameters:

`state` - the current state of our dogs in adoption.

 `action` - an object that contains the following:

 - `type` of action we want to perform. In this case, we are only building two options, `adopt` or ‘return’.

 - `payload` optional data. In our example, we will pass the dog’s `name` so we can identify which dog got adopted or returned.

```javascript
const reducer = (state, action) => {
  switch (action.type) {
    case 'ADOPT':
      return state.map(dog => {
        if (dog.name === action.payload) dog.adopted = true;
        return dog;
      });
    case 'RETURN':
      return state.map(dog => {
        if (dog.name === action.payload) dog.adopted = false;
        return dog;
      });
    default:
      return state;
  }
}
```

Now It’s finally time to implement our ***useReducer()*** hook! Take a look at the example below, where we define our ***useReducer()*** hook with the `initialState` (adoption dogs list) and the `reducer` function we created to handle their adoption status. 

We iterate through our dogs list state and display a button that will say `adopt` or `return` depending on their current adoption status. The `onClick` handler assigned to our button will call a function in charge of using the `dispatch` function returned by our ***useReducer()*** hook passing the `type` of action it needs to perform and the dog’s name as `payload`.

```javascript
const adoptDog = name => dispatch({ type: 'ADOPT', payload: name });
```

The `dispatch` function will pass this data to our `reducer` function, where we will use the `type` to identify what section of code needs to run and the `payload` to find the dog record we need to update.

{% codepen https://codepen.io/Milu5489/pen/vYLaEzB %}

## When should you use useReducer?

When explaining the ***useReducer*** hook, we compared it to ***useState*** so you might be wondering… when should I use ***useReducer*** and when should I use ***useState***?

The ***useReducer*** hook is a preferred alternative to ***useState*** when dealing with the following:

- Complex state logic that involves multiple sub-values
- State values that depend on the state of other state elements

## Summary

- The JavaScript ***reduce*** method is very useful when you want to obtain a single value after applying some logic to a group of values.

- ***reducers*** return a new value instead of mutating your initial value.

- The ***useReducer*** hook is used with state management.

- The ***useReducer*** hook should be used when dealing with complex state logic, multiple sub-values, or when your state depends on state sub-values.

---

I hope this post helped you get a better understanding of the JavaScript ***reduce*** method and the ***useReducer()*** hook and that you will start taking advantage of these concepts in your future projects.

I enjoy creating content that explains concepts in really simple terms. ***Why?*** Because knowledge is power and I want to help beginner developers expand their knowledge and thrive.

Give this post a reaction if you found it helpful and follow me on [Twitter](https://twitter.com/milu_franz) and [Dev.to](https://dev.to/milu_franz) to keep up with new posts!