useState or useReducer – which to choose for your application
Tags: react, reacthooks, javascript, frontend
Published: 2023-04-04 03:20:44

`useReducer` helps us manage state in a complex application. What exactly is `useReducer`? Is it an alternative to `useState`? `useState` and `useReducer` are both used to handle state logic. It is thereby necessary to understand when to use these hooks. `useReducer` is not replacing `useState` in any way but it would be more efficient to use `useReducer` in some complex applications.

We are going to explore these hooks in detail showing the best hook to use in any given application and how we can convert one of these hooks to use the other. Let’s get started.

The commonly used state hook – `useState`, is a react hook that lets you add a state variable to your component. It is usually written like this:

`const [state, setState] = useState(initialState)`

`useState` takes in an initialState which can be a string, boolean, number, array, object or function. It returns two values namely:

1. state – This is the current state
2. setState – This is a function that updates the state.

A simple example looks like this:

```
const [country, setCountry] = useState('Nigeria');
const handleClick = () => {
    setCountry('South Africa');
}
```

The above code snippet is a simple example of the `useState` hook and how we can use it to update the state. If the `handleClick` function is passed to a button, on clicking the button, the application re-renders to show the update – “South Africa” for the country state variable.

### What exactly is useReducer?

`useReducer` is a React hook that lets you add a reducer to your component. So, what is a reducer? A reducer is a function that allows us to specify all the state update logic in a single function.

`useReducer` takes in two major parameters and an optional third parameter. It returns two values – state and dispatch. The state is the current state and the dispatch is a function that lets you update the state.

`const [state, dispatch] = useReducer(reducer, initialState, initFunc?)`

Same simple example with `useReducer`:

```
const reducer = (state, action) => {
    switch (action.type) {
        case 'change_country': {
            return {
                country: action.newCountry
            }
        }
        // other cases are written here
        default: {
            return state
        }
    }
}

const [state, dispatch] = useReducer(reducer, {country: 'Nigeria'});

const handleClick = () => {
dispatch({
    type: 'change_country',
    newCountry: 'South Africa'
})
}
```
An explanation of the above sample code snippet – we invoked our `useReducer` which accepts a reducer that contains the logic for updating the state and an initial state of `{ country: ‘Nigeria’ }`. We are calling the dispatch function in the click handler; passing in the type of action we want to perform with the value of the next state.

### Dispatch and Reducer Explained

Dispatch Function: The dispatch function returned by `useReducer` lets you update the state to a different value and trigger a re-render. You need to pass the action as the only argument to the dispatch function. An action is usually an object with a type property identifying it and, optionally, other properties with additional information.

```
dispatch({
    type: ‘change_country’,
    // other properties
})
```
A reducer function is declared like the below code snippet. It accepts state, which is the current state and action which updates the state and returns the next state.

```
function reducer(state, action) {
    // state updates are made here
}
```

We have successfully updated a state using both `useState` and `useReducer`. So, of what use is one hook over the other? We will cover this next in this article.

### Comparing useState and useReducer

- `useReducer` is similar to `useState`. `useReducer` enables us to move our state update logic into a single function which is more efficient for larger applications.

- `useState` is simple and easy to set up for smaller applications but when the application gets complex, it becomes difficult to read with many state logic in event handlers. `useReducer` proves to be efficient for this use case as it helps organize our state logic in one place.

- `useReducer` is easier to debug in a complex application as you can easily find the action that is not dispatched, but with `useState`, you would have to look through a lengthy code to identify the error.

- Examining the above code sample, using `useState` resulted in fewer lines of code. While this is good for smaller applications when the application gets larger, the lines of code also increase. Using `useReducer` to separate the logic in a function is a better approach for larger applications.

If your application is handling multiple state logic in event handlers, then you should use `useReducer` else `useState` is fine.

### How to migrate from useState to useReducer.

We are going to explore an example that uses both `useState` and `useReducer`. You will, therefore, see how we can migrate from one to the other. Here is a simple application that gets the user’s `first_name` and `last_name` with a button to add the names to the existing name list and a button to reset the name list.

Steps to follow:

- Move from setting state to dispatching actions.
- Write a reducer function.
- Use the reducer from your component.

This contains the [code ](https://codesandbox.io/s/usestate-and-usereducer-hook-example-9lmkm9?file=/src/App.js)sample of our application. To see the implementation of our state update logic using `useState`, comment out the FormUsingReducer component in App.js and uncomment the Form component in App.js and vice-versa for `useReducer`.

### Conclusion

We have explored both `useState` and `useReducer` to update state. We also looked at a real live example, when it is preferable to use these hooks and lastly a quick comparison of both. A lot of references are from the React documentation. Check it out [here](https://react.dev/reference/react).

Understanding the concepts we use and exploring new concepts is critical for growth as developers. I hope you have learned something and you are excited about applying what you have learnt in your next project.

Thanks for reading.