Redux createAsyncThunk 与 useEffect 钩子

问题描述 投票:0回答:4

我熟悉react hooks,我发现使用useEffect非常容易,thunk很难处理,我可以只使用useEffect和axios并将结果分派到商店而不使用createAsyncThunk吗?使用它比 useEffect 有什么主要的性能优势吗?

创建AsyncThunk:

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))

使用效果:

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}));
    }, []);
javascript reactjs redux react-redux
4个回答
7
投票

这两种设置本质上是相似的。您可以使用两种方法做同样的事情。

如果代码与您在此处编写的代码完全相同,则

createAsyncThunk
方法有一个主要优点,因为它会
catch
API 调用中发生的任何错误。它将通过调度
fetchUserById.rejected
操作而不是
fetchUserById.fulfilled
操作来响应这些错误。您的减速器没有响应
rejected
的情况,这很好。错误仍然被捕获。使用您的
useEffect
,您将面临“Promise 中未捕获的错误”错误的风险。

现在您当然可以自行

catch
纠正错误。您还可以在效果开始时执行
dispatch
pending
操作。但是,一旦您开始这样做,相比之下,
createAsyncThunk
可能会感觉容易得多,因为它会自动调度
pending
fulfilled
rejected
操作。

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

1
投票

不返回

response.data
,只需返回 api 调用而不等待。这样你就有了已完成、已拒绝状态。

您的问题是您需要这些数据做什么?仅在这个组件中还是在多个组件中?您也可以使用 context api 来在组件之间实现更高的数据共享,但说实话,如果您是 React 的初学者,我会在介绍 redux 之前了解 hooks 并做出很好的反应。通常生产应用程序(不是说 100% 但大多数)使用某种异步状态管理。您还可以研究react-query作为如何处理异步内容的另一个选项。


1
投票

琳达·派斯特是正确的。 只是为了进一步扩展您问题的答案,另一个非常流行的选项是TanStack Query(React Query)。它可以满足您的要求:

const { isLoading, error, data } = useQuery(['repoData'], () =>
    fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
      res.json()
    )
  )
  1. 它很好地处理了
    repoData
    中的缓存,类似于 RTKQ。
  2. 它会将响应状态
    isLoading, error, data
    返回给您,就像 RTKQ 一样。
  3. 您可以自由使用 RESTful
    axios
    fetch
    或任何非 RESTful 请求。
  4. IMO它更紧凑,更容易更短的学习曲线,对于初学者来说没有满口奇怪的单词,例如切片减速器额外减速器thunk...等等

0
投票

与繁琐的thunk相比,thunk的灵活性、高内聚性、异步转同步的书写方式确实非常出色。您通常希望使用 hooks 而不是 thunk 来处理异步,然后直接更新到存储。这是因为你混淆了双方的责任:

Thunk 处理应用模型层的业务,该层通常依赖于多个组件。 ⚠️这里所说的业务不仅仅是数据,还包括pending、fulfilled、redirected或者其他状态等流程。

而hooks只能为单个组件提供这些状态和数据,除非你写各种上下文,但是这还是比thunk的写法不太友好

所以原则是,你首先需要分析业务是否是模型级的、公共的,其数据/流程将来可能会依赖于多个组件。一旦完成,您就不应该厌倦将其添加到 thunk 中。否则,你应该使用钩子

© www.soinside.com 2019 - 2024. All rights reserved.