最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Redux createAsyncThunk vs useEffect hook - Stack Overflow

programmeradmin3浏览0评论

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}));
    }, []);

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}));
    }, []);
Share Improve this question asked Apr 11, 2021 at 0:05 tokochitokochi 3063 silver badges7 bronze badges 1
  • 2 The question you want to ask yourself is "which part of my app do I want responsible for handling async API calls?" and then use the tools at that level to handle that. If you believe your visual ponent should handle that, then use useEffect; if you think your redux state should, then use the createAsyncThunk tool. Separation of responsibilities is very helpful in creating clear boundaries for what a thing should do, and makes for much easier testing and hunting down bugs if they occur. – Derek Commented Apr 11, 2021 at 2:10
Add a ment  | 

3 Answers 3

Reset to default 7

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 parison 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 ponent or more than 1 ponent? You can use the context api as well for higher sharing of data among ponents, 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.

Linda Paiste is correct. Just to extend the answer to your question a bit further, the other very popular option is TanStack Query (React Query). It gives you what you are asking for:

const { isLoading, error, data } = useQuery(['repoData'], () =>
    fetch('https://api.github./repos/tannerlinsley/react-query').then(res =>
      res.json()
    )
  )
  1. It nicely takes care of the caching in repoData similar to RTKQ.
  2. It returns the response status isLoading, error, data back to you, again just like RTKQ.
  3. You can use RESTful axios or fetch or any non-RESTful request freely.
  4. IMO it is more pact, easier shorter learning curve, without mouthful of weird words for beginners like slice reducer extra redeucer thunk...etc
发布评论

评论列表(0)

  1. 暂无评论