Additional Hooks in React - useReducer()
Tags: react, javascript, webdev, beginners
Published: 2021-01-19 16:46:34

This blog post continues the series about [React Hooks](https://reactjs.org/docs/hooks-reference.html ).

It covers one of additional hooks in React - **useReducer()**.

## What is useReducer()?

**useReducer()** is JavaScript function, which allows to use  reducer functions from state management in *functional component*.  It is an alternative to `useState()` hook and as react developers say : "New one and improved" :)

Before you read any further, you should be familiar with [state management](https://olena.hashnode.dev/managing-state-with-react-context) and [reducers](https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers). 

## How and when use useReducer()

To use this hook, you need to import it first from React library like this:

```react
import {useReducer} from 'react';
```
You can use this hook without import as well like this - `React.useReducer()`, for me it's just more convenient to import and destructure first this function and then use it when need in the code.

Afterwards we can set up this hook like this:

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

Let's examine this example  more detailed. 

NOTE: If you are familiar with Redux, you already know how it works

**useReducer** hook :
-  accepts *reducer function* and *initial state*.
- returns *current state* and *dispatch method*

Let's consider the following example - we are building an app which is a simulation of the farm. 

Here’s a store of data, where we have four hungry animals (this is our `initialState`):

```react
const animals = [
  {type: 'horse', isHungry: true},
  {type: 'sheep', isHungry: true},
  {type: 'cow', isHungry: true},
  {type: 'pig', isHungry: true}
]
```

Let’s create a `reducer` to feed them:

```react
const animalsReducer = (animals, action) => {

  if(action.type == 'feed') {
    return animals.map(animal => {
      if(animal.type == action.specificAnimal) {
        animal.isHungry = false;
      }
      return animal;
    })
  }
  if(action.type == 'giveWater') {
    return animals.map(animal => {
      if(animal.type == action.specificAnimal) {
        animal.isHungry = true;
      }
      return animal;
    })
  }
}
```

So, the important thing to notice here is what we pass to our `animalsReducer` function: our **initial state** (animals) and **action** (you could think of this as a setState method). The `action.type` identifies what type of action we want to do and `action.specificAnimal` identifies for us which animal we want to perform the action on.

Now that we have our reducer and store setup, let’s implement them with our **useReducer()** hook:

```react
const [state, dispatch] = useReducer(animalsReducer, animals);
```
And finally let's implement our `dispatch` functions and use them in JSX:

```react
const feed =(animalType)=>{dispatch({ type: 'feed', specificAnimal: animalType });}

const giveWater = (animalType) => {dispatch({ type: 'giveWater', specificAnimal: animalType });}

return (
  <div>
    {state.map((animal, idx) => (
      <div key={idx} style={{ display: 'flex', width: '50%', justifyContent: 'space-around' }}>
        <div>{animal.type}</div>
        {animal.isHungry ?
          <div>NOT HUNGRY! <button onClick={() => feed(animal.type)}> feed </button> </div> :
          <div>HUNGRY<button onClick={() => giveWater(animal.type)}> give water</button> </div>}
      </div>
    ))}
  </div>
)
```

The dispatch method receives an object that represents the action we desire to be done. We pass our action to our reducer through the useReducer. Our reducer returns updated state.

## CONCLUSION

You can use `useState` in the same component or hook that's using `useReducer` and you can have multiple useStates and multiple useReducers in a single hook or component.
**useReducer** is usually preferable to **useState** when you have complex state logic that involves multiple sub-values or when the next state depends on the previous one. 
useReducer also lets you optimize performance for components that trigger deep updates because you can pass dispatch down instead of callbacks.

Thank you for reading my blog. Feel free to connect on [LinkedIn](https://www.linkedin.com/in/olenadrugalya/) or [Twitter](https://twitter.com/OlenaDrugalya) :)

<a href='https://ko-fi.com/J3J42JOOA' target='_blank'><img height='12' width=30% style='border:0px;height:12px;' src='https://cdn.ko-fi.com/cdn/kofi1.png?v=2' border='0' alt='Buy Me a Coffee at ko-fi.com' /></a>