Asynchronous React Redux with Action Creators

Asynchronous React Redux with Action Creators

This article shows how to implement asynchronous code and side effects in Redux. As explained in the previous article React Redux & Redux Toolkit, Redux reducers must be pure, side effects free and synchronous. However, there are two alternatives to store or load some data from the back-end server:

  • Components

  • Action creators

The first option is feasible, but it would increase the logic of the component and make it harder to read. The second option is ideal, as all logic remains in the slice.js file where it belongs. Redux Toolkit automatically creates action creators that can be called to create action objects to be dispatched. However, it is also possible to create custom action creators called thunks. A thunk is a function that delays an action until something else is done. Such a function simply returns another function that returns an action, allowing the developer to execute a asynchronous code before sending the actual action object.

import {createSlice} from "@reduxjs/toolkit";
import {uiActions} from "./ui-slice";

const cartSlice = createSlice({
    name: 'cart',
    initialState: {...},
    reducers: {
        addItemToCart(state, action) {...},
        removeItemFromCart(state, action) {...}
    }
})

// CREATING A FUNCTION
export const sendCartData = (cart) => {
    // IT RETURNS ANOTHER ASYNC FUNCTION WHICH ACCEPTS A DISPATCH FUNCTION
    return async (dispatch) => {
        // DISPATCHING ACTION FROM OTHER SLICE TO NOTIFY THE PENDING PROCESS
        dispatch(uiActions.showNotification({
            status: 'pending',
            title: 'Sending..',
            message: 'Sending cart data'
        }))
        // CREATING ANOTHER NESTED FUNCTION TO RUN HTTP REQUESTS
        const sendRequest = async () => {
            const response = await fetch('https://any-link-to-somebackend.com', {
                method: 'PUT',
                body: JSON.stringify(cart)
            })
            if (!response.ok) {
                throw new Error('Sending cart failed.')
            }
        }
        // CALLING THE FUNCTION INSIDE A TRY/CATCH TO HANDLE ERRORS
        try {
            await sendRequest()
            // DISPATCHING SUCCESS NOTIFICATION
            dispatch(uiActions.showNotification({
                status: 'success',
                title: 'Success',
                message: 'Sent cart data successfully!'
            }))
        } catch (err) {
            // DISPATCHING ERROR NOTIFICATION
            dispatch(uiActions.showNotification({
                status: 'pending',
                title: 'Sending..',
                message: 'Sending cart data'
            }))
        }
    }
}

export const cartActions = cartSlice.actions
export default cartSlice

Now the sendCartData function can be dispatched within any component as any other action:

dispatch(sendCartData(cart));

🍭 Links

⚜️ Thanks to Maximilian Schwarzmüller, you can find his React course here.

⚜️ Find the complete code on my GitHub.

⚜️ Connect with me on LinkedIn.

⚜️ Or follow me on Instagram if you are curious about my life!

If you liked the content, please leave some likes 🤙❤️ or unicorns 🦄

Pietro Piraino 🐈‍⬛🇮🇹🍕