DEV Community

Cover image for Complete guides to React useReducer() Hook
Ahmad Mkahal
Ahmad Mkahal

Posted on

Complete guides to React useReducer() Hook

useReducer() is a React.js Hook which manage complex state in your application and update it based on the 'action' you send to.
It's used as an alternative for useState if you have a complex states or can be used both together according to your application requirements.
It's very similar to Redux if you want to not use a 3rd-party library.

First

You should import useReducer from react js

import React, { useReducer } from 'react';
Enter fullscreen mode Exit fullscreen mode

Second :

useReducer Hook accepts a reducer function, and an initial state.
It's returns an array with 2 values:
The first one is the state value, and the second value is the dispatch function which is used to trigger an action with the help of ES6 destructuring.

const [state, dispatch] = useReducer(reducer, initialState);
Enter fullscreen mode Exit fullscreen mode
initialState :

The initial state that we want to start working on it

reducer :

Which we'll use to manipulate our state.

Let's go with simple example

Let's say you're displaying some products in your app, and you want to :

  • Add a product to the cart when user click on add to cart button and list it in cart page.
  • Remove the product from cart list if the user click on remove from cart button.
  • User can switch the application (dark/light mode)

Create Reducer.js component to add our reducer in it.

How to use it ?

  • Firstly, we will define the reducer function that will manipulate our state:
// Reducer.js
const reducer = (state, action) => {
  // reducer function accepts two arguments 
  /* 
   the first one is `state` which is going to be the state 
   before the update.
  */ 
  /* 
   the second one is `action` which is what are we trying to do.
  */ 
}

export default reducer;
Enter fullscreen mode Exit fullscreen mode
  • Second step, we will define the initial state object which contains our initial values :

    1- cart array property which holds products user added to his/her cart.

    2- mode property which holds the app mode and it's by default will be light.

We'll put those in our file, but outside of the component:

// Reducer.js
export const initialState = {
    cart: [],
    mode: 'light'
};

const reducer = (state, action) => {
    switch (action.type) {
        case 'ADD_TO_CART':
            return {
                ...state,
                cart: [...state.cart, action.item]
            };

        case 'REMOVE_FROM_CART':
            const index = state.cart.findIndex(item => action.id === item.id);
            let newCart = [...state.cart];
            if (index >= 0) {
                newCart.splice(index, 1);
            }

            if (newCart.length === 0) {
                return {
                    ...state,
                    cart: newCart,
                }
            } else {
                return {
                    ...state,
                    cart: newCart,
                }
            };
        case 'CHANGE_MODE':
            return {
                ...state,
                mode: action.mode
            }
        default: return state
    }

}

export default reducer;
Enter fullscreen mode Exit fullscreen mode

Now, let's imagine we have a Product.js component that return a products to be displayed in your app.

// Product.js
import React from 'react'

function Product({ name, image }) {
    const addToCart= () => {
        // some code
    }
    return (
        <div className="product">
            <img src={`${image}`} />
            <p>{name}</p>
            <button onClick={addToCart}>add to cart</button>
        </div>
    )
}

export default Product

Enter fullscreen mode Exit fullscreen mode
  • The fourth step, our reducer is all setup, now let's define then use it. To be able to use the reducer function you must define it in everywhere you need like so:
import React, {useReducer} from 'react'
import reducer, {initialState} from './Reducer';

function Product({ name, image }) {
    const [state, dispatch] = useReducer(reducer, initialState) ;
    .
    .
    .
Enter fullscreen mode Exit fullscreen mode

Firstly you need to import useReducer from React, then import the reducer and initialState to be used.
Now we will define our reducer using useReducer() hook

const [state, dispatch] = useReducer(reducer, initialState) ;
Enter fullscreen mode Exit fullscreen mode

The useReducer hook will return two things in an array: the state, and a dispatcher to update the state.

We will grab those with array destructuring, similar to state and setState with the useState.

Dispatch actions :

Every time the user clicks on add to cart button, addToCart function will be called to dispatch the action to the reducer function to do some changes in that state.
So, the addToCart function will contains the following code :

const addToCart= () => {
        dispatch({
            type: 'ADD_TO_CART',
            item: {
                image,
                name
            }
        })
    }
Enter fullscreen mode Exit fullscreen mode

We sent the action name to the reducer function to know what kind of changes will be happened, in this case the action is ADD_TO_CART action. Also we sent the item or the product which user need to add to the card to be added to the state.cart array.

So, the Product.js component will be :

import React, {useReducer} from 'react'
import reducer, {initialState} from './Reducer';

function Product({ name, image }) {
    const [state, dispatch] = useReducer(reducer, initialState) ;
    const addToCart= () => {
        dispatch({
            type: 'ADD_TO_CART',
            item: {
                image,
                name
            }
        })
    }
    return (
        <div className="product">
            <img src={`${image}`} />
            <p>{name}</p>
            <button onClick={addToCart}>add to cart</button>
        </div>
    )
}

export default Product

Enter fullscreen mode Exit fullscreen mode

We will be satisfied with ADD_TO_CART, others actions will be the same but with deferent functionality

Accessing state

Now you can accessing the state and make on it anything you want like mapping cart array and so on.

Conclusion

  • useReducer Hook is extremely useful when working on complex and different states depend on each other.

  • useReducer is very similar to Redux if you want to not use a 3rd-party library or if it's only for a component or two.

Hope this article helped you to understand useReducer hook what is exactly.

Thanks for reading 🙌
-Ahmad Mukahal

Discussion (2)

Collapse
pavelee profile image
Paweł

really great explanation! Thanks!

Collapse
ahmedm1999 profile image
Ahmad Mkahal Author

Thank you and good luck