有关使用createAysncThunk的问题

问题描述

我是redux和redux工具包的新手。我正在从redux工具箱官方文档中阅读本教程。 https://redux-toolkit.js.org/api/createAsyncThunk。这是它提供的示例

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

const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',async (userId,{ getState,requestId }) => {
    const { currentRequestId,loading } = getState().users
    if (loading !== 'pending' || requestId !== currentRequestId) {
      return
    }
    const response = await userAPI.fetchById(userId)
    return response.data
  }
)

const useRSSlice = createSlice({
  name: 'users',initialState: {
    entities: [],loading: 'idle',currentRequestId: undefined,error: null
  },reducers: {},extraReducers: {
    [fetchUserById.pending]: (state,action) => {
      if (state.loading === 'idle') {
        state.loading = 'pending'
        state.currentRequestId = action.Meta.requestId
      }
    },[fetchUserById.fulfilled]: (state,action) => {
      const { requestId } = action.Meta
      if (state.loading === 'pending' && state.currentRequestId === requestId) {
        state.loading = 'idle'
        state.entities.push(action.payload)
        state.currentRequestId = undefined
      }
    },[fetchUserById.rejected]: (state,action) => {
      const { requestId } = action.Meta
      if (state.loading === 'pending' && state.currentRequestId === requestId) {
        state.loading = 'idle'
        state.error = action.error
        state.currentRequestId = undefined
      }
    }
  }
})

const UsersComponent = () => {
  const { users,loading,error } = useSelector(state => state.users)
  const dispatch = usedispatch()

  const fetchOneUser = async userId => {
    try {
      const resultAction = await dispatch(fetchUserById(userId))
      const user = unwrapResult(resultAction)
      showToast('success',`Fetched ${user.name}`)
    } catch (err) {
      showToast('error',`Fetch Failed: ${err.message}`)
    }
  }

  // render UI here
}

我的问题是,因为我们已经处理了生命周期动作创建者即诺言被拒绝的情况。

[fetchUserById.rejected]: (state,action) => {
      const { requestId } = action.Meta
      if (state.loading === 'pending' && state.currentRequestId === requestId) {
        state.loading = 'idle'
        state.error = action.error
        state.currentRequestId = undefined
      }
    }

那么,为什么在UsersComponent中,我们仍然需要尝试捕获由调度程序引发的错误。我们是否不能从error状态得知请求是否失败?更清楚地说,我如何通过以下方式写UsersComponent


const UsersComponent = () => {
  const { users,error } = useSelector(state => state.users)
  const dispatch = usedispatch()

  useEffect(() => {
    dispatch(fetchUserById(userId))
  },[dispatch])

  if(error) {
    showToast('error',`Fetch Failed: ${error.message}`)
  } else if(loading) {
    showToast('loading')
  } else {
    showToast('success',`Fetched ${user.name}`)
  }

  // render UI here
}

此外,我不知道何时会派遣fetchUserById.rejected?根据文档,createAsyncThunk将始终返回已解决的承诺。如果我们在createAsyncThunk

的回调中达到此条件
if (loading !== 'pending' || requestId !== currentRequestId) {
      return
    }

那么,分派生命周期操作将是fulfilled对吗?派遣rejected生命周期动作需要什么?仅当回调内部引发异常时?

我的最后一个问题是,例如,如果我想检查返回的数据是否正确,我想确定是否有一个名为data属性。我该如何实现?如果我将createAsyncThunk中的回调重写为


const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',loading } = getState().users
    if (loading !== 'pending' || requestId !== currentRequestId) {
      return
    }
    const response = await userAPI.fetchById(userId)
    if(!response.data) throw new Error('No data')
    return response.data
  }
)

rejected上实际上没有data属性的情况下,是否会分派response生命周期操作?

解决方法

关于您问题的第一部分: 是的,您可以在后续渲染中执行此操作。 但是如果你只是写

  if(error) {
    showToast('error',`Fetch failed: ${error.message}`)
  } else if(loading) {
    showToast('loading')
  } else {
    showToast('success',`Fetched ${user.name}`)
  }

会在随后对该组件的个渲染中显示敬酒。在React中,每次渲染父对象时,该组件都会重新渲染,因此您可能会看到很多Toast。

您当然也可以使用useEfect,然后,如果您更喜欢的话,可以这样做。那只是一种风格,有些人喜欢一种更好的方式,另一种喜欢。

例如,rejected可能由于网络问题而引发错误时,将调度userAPI.fetchById动作。

如果仅调用return ,它将实际上返回undefined并导致以undefined作为有效载荷的已完成操作。