Steps to add async logic  in React + redux app using createAsyncThunk

Steps to add async logic in React + redux app using createAsyncThunk

Redux does everything synchronously , and for that reason we need to use redux middleware ,The Most common async middleware is Redux Thunk

·

3 min read

If you know anything about how to use redux-toolkit with React app , Please check this Link before starting this article : Steps to use redux-toolkit with React app

Getting Started

Step 01: Add the status and the error fields to your initial state

const initialState = {
  posts: [],
  status: 'idle',
  error: null ,   
  }

Step 02: Import the createAsyncThunk

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'

Step 03: Create the Thunk using createAsyncThunk

CreateAsyncThunk accepts two arguments :

  • Prefix for the Action Type

  • Payload creator callback returns promise ( date or rejection )

      const fetchPosts = createAsyncThunk(
        'posts/fetchPosts', async () => {
          try{
              const response = await axios(URL)}
              return [...response.date]
          }catch(error) {
              return error.message
          }
      )
    

Step 04: Respond to thunk actions

The async thunk action ( fetch ) is not defined in the slice's reducers, which means the slice reducer can not respond to them, so in this case we add the extraReducer.

  1. The extraReducer accepts a builder param

  2. The builder param lets us define additional reducers for the additional action types.

Each promise status ( action type ) has a reducer, a promise could be :

  1. Pending :

     builder.addCase(fetchPosts.pending, (state, action) => {
           // set status : loading 
           state.status = 'loading'
         })
    
  2. Fulfilled

     builder.addCase(fetchPosts.fulfilled, (state, action) => {
           // set status : succeeded 
           state.status = 'succeeded' 
          // set state : data 
           state.posts = action.payload 
         //...
         })
    
  3. Rejected

     builder.addCase(fetchPosts.rejected, (state, action) => {
           // set status : failed 
           state.status = 'failed' 
          // set state : data 
           state.error = action.error.message 
         //...
         })
    

Global code :

const initialState = {
  posts: [],
  status: 'idle',
  error: null ,   
  }
const usersSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {
    // standard reducer logic
  },
  extraReducers: (builder) => {
    // Add reducers for additional action types .
/* 1. pending */
    builder.
        addCase(fetchPosts.pending, (state, action) => {
          // set status : loading 
          state.status = 'loading'
        })
/* 2. Fulfilled */
        .addCase(fetchPosts.fulfilled, (state, action) => {
              // set status : succeeded 
              state.status = 'succeeded' 
             // set state : data 
              state.posts = action.payload 
            //...
            })    
/* 3. Rejected */
        .addCase(fetchPosts.rejected, (state, action) => {
              // set status : failed 
              state.status = 'failed' 
             // set state : data 
              state.error = action.error.message 
            //...
            })      
  },
})

Step 05: Add the result to the UI

  1. Import the UseSelector , useDispatch , slice reducers and fetch function :

     import { useSelector, useDispatch } from 'react-redux'
     import { /* reducers */ , fetchPosts } from './postsSlice '
    
  2. read the status and error :

     const error = useSelector((state) => state.posts.error)
     const status = useSelector((state) => state.posts.status)
    
  3. define the dispatch :

         const dispatch = useDispath()
    
  4. Dispatch the fetch whenever we want :

     dispatch(fetchPosts())
    

    Exemple:

     useEffect(() => {
         if( status  === 'idle' ){
             dispatch(fetchPosts())
           }
     } , [status , dispatch])
    

THIS IS THE END , THANK YOU FOR READING .