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}));
}, []);
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 })
);
}, []);
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With