useReducer() hook - Redux inside your component
Tags: webdev, react, javascript
Published: 2023-07-14 17:53:03

Hey There 👋🏾

Welcome to another post in the **React demystified** series. 

Last week, we dug deep into the concept of `Context` in React👇🏾
{% embed https://dev.to/kokaneka/mastering-reacts-context-a-guide-to-efficient-state-propagation-4804 %}

This week, we look into `useReducer`. Let's do it 🙌🏾

---

### Use case for useReducer
Let us try to explore the use cases where we would think about using the `useReducer` hook. 
Before that, let us start off with a simple example. If we had to write the code for a simple component that holds a **count** as state, here's how we would write it:

``` jsx
const [count, setCount] = useState(0)
```

The code above initialises the state to 0. We also have **count** through which we can access the current value of the state and `setCount` through which we can set a value of the state. 

If we need to set the value of the state, it's quite straight forward, we call `setCount`:

``` jsx
setCount(10);
```

But, what if we want to perform several operations on the state?

### Operations on the state
Let us say that we have the state and several operations that we want to perform on the state like **increment**, **decrement**, **reset** (to 0), and **set** (to a custom value). 

> In that case, the code could be designed in such a way that we take the state, perform an action on it: **INCREMENT**, **DECREMENT**, **RESET** or **SET** and the we get the new value. 

But what we defined above is the textbook definition of a reducer function!
![A reducer function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azh377ulhyfz5mfo1d15.png)

And thus, our use case can be accomplished with the `useReducer` hook because it allows us to create a _reducer_ inside of our React component. 

### Writing the reducer
With that understanding, let us write our *reducer* function. This is the function that React will call with the current state and the dispatched event type (whenever we dispatch one).

``` jsx
function reducerFunc(state, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    case 'RESET':
      return 0;
    case 'SET':
      return action.val;
  }
}
```

And that's it. With just those lines of code, we've set up state management for our complex use case. 

> ☝🏾 Do not that the example of state to be a single number is just for the sake of explaining the concept and in react world, you would have complex objects as your core state and your would have to write logic inside your reducer to manage it correctly. 

With that reducer, we can then initialise everything like so:
``` jsx
const [state, dispatch] = useReducer(reducerFunc, 0);
return (
    <main>
      <h1>Count : {state}</h1>
// rest of the code
```

And, whenever we need to dispatch any changes to the state, we do something like this:

``` jsx
<button onClick={() => dispatch({ type: 'INCREMENT' })}>increment</button>
```

And React will take care of the rest. 

### The reducer flow
Basically, this is what happens when we call the `dispatch` function provided to us by `useReducer`:
- React calls the function that you initially supplied to `useReducer` and passes to it the arguments we supplied to `dispatch`. 
- The reducer function then makes some calculations based on some business logic. 
- The value that gets returned by the reducer function becomes the new **state**

This graphic sums it up well:

![reducer flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bl7n2m9skof16x1ohan6.png)

So basically, it is like having entire redux inside the scope of your React component. 

Hope that clears a lot of confusion around the `useReducer` hook and the basic concept of a **reducer** function. 

Cheers! 🙌🏾