Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux createAsyncThunk vs useEffect hook

Tags:

I'm familiar with react hooks, and i find it really easy to work with useEffect, thunk is very difficult to deal with, can i just use useEffect & axios and just dispatch the result to the store without using createAsyncThunk? is there any major performance benefit to use it over useEffect?

createAsyncThunk:

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

// First, create the thunk
const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId)
    return response.data
  }
)

// Then, handle actions in your reducers:
const usersSlice = createSlice({
  name: 'users',
  initialState: { entities: [], loading: 'idle' },
  reducers: {
    // standard reducer logic, with auto-generated action types per reducer
  },
  extraReducers: {
    // Add reducers for additional action types here, and handle loading state as needed
    [fetchUserById.fulfilled]: (state, action) => {
      // Add user to the state array
      state.entities.push(action.payload)
    }
  }
})

// Later, dispatch the thunk as needed in the app
dispatch(fetchUserById(123))

useEffect:

import React, { useEffect } from 'react';
import { useDispatch } from 'react-redux'
import { userAPI } from './userAPI'
import axios from 'axios';
 
function App() {  
const dispatch = useDispatch()
useEffect(() => {
axios
  .get(userAPI)
  .then(response => dispatch({type:'fetchUsers',payload:response.data}));
    }, []);
like image 590
tokochi Avatar asked Apr 11 '21 00:04

tokochi


2 Answers

The two setups are essentially similar. You can do the same thing with both approaches.

With the codes exactly as you have them written here, there is a major advantage to the createAsyncThunk approach because it will catch any errors that occur in the API call. It will respond to those errors by dispatching a fetchUserById.rejected action instead of a fetchUserById.fulfilled action. Your reducer doesn't responded to the rejected case which is fine. The error is still caught. With your useEffect you run the risk of "uncaught error in Promise" errors.

Now of course you can catch the errors on your own. You can also dispatch a pending action at the start of the effect. But once you start doing that, the createAsyncThunk might feel a lot easier by comparison since it automatically dispatches pending, fulfilled, and rejected actions.

useEffect(() => {
  dispatch({ type: "fetchUsers/pending" });
  axios
    .get(userAPI)
    .then((response) =>
      dispatch({ type: "fetchUsers", payload: response.data })
    )
    .catch((error) =>
      dispatch({ type: "fetchUsers/rejected", payload: error.message })
    );
}, []);
like image 146
Linda Paiste Avatar answered Oct 01 '22 20:10

Linda Paiste


Instead of returning response.data just return the api call without the await. That way you have the fulfilled, rejected statuses.

As for your question is a matter of what do you need this data for? Just in this component or more than 1 component? You can use the context api as well for higher sharing of data among components, but to be honest if you are a beginner with react I would understand hooks and react well before you introduce redux. Usually production apps, not to say 100% but the majority, use some kind of state management with async. Also you can look into react-query as another option on how to handle async stuff.

like image 27
Luis Villavicencio Avatar answered Oct 01 '22 20:10

Luis Villavicencio