【发布时间】:2020-12-09 10:22:03
【问题描述】:
我是 redux 和 redux 工具包的新手。我正在阅读 redux toolkit 官方文档中的本教程。 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中,我们还需要尝试捕获dispatch抛出的错误。难道我们不能从error状态判断请求是否失败吗?为了更清楚,我这样写UsersComponent怎么样:
const UsersComponent = () => {
const { users, loading, 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',
async (userId, { getState, requestId }) => {
const { currentRequestId, 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
}
)
当response 上实际上没有data 属性时,rejected 生命周期操作是否会被调度?
【问题讨论】:
-
请针对每个帖子关注一个问题,对于您的第一个问题:您的示例将无法运行,因为您发送了
asyncThunk,它返回了一个承诺,您可以轻松检查您的代码。跨度> -
@DennisVash 它确实有效。我知道它会返回一个承诺。但是通过调度
asyncThunk,thunk 将调度待处理的动作,如果承诺成功解决,则调度已完成的动作,承诺值为 action.payload。 -
那么问题出在哪里?如果它工作那没关系
-
@DennisVash 帖子的问题中说明了问题。如果你不想回答为什么不能忽略这个问题
标签: javascript reactjs redux redux-toolkit