带有 Redux 工具包的通用加载状态缩减器
Common loading state reducer with Redux toolkit
我正在开发一个有多个切片的应用程序。我将 createAsyncThunk
用于 API 调用,我喜欢它,因为它为 API 请求的不同状态提供了动作创建器,以便我可以跟踪加载状态和减速器中的错误。但我的问题是,如果我想有一个单独的减速器来跟踪我的 API 调用的 loading
、error
和 success
,我该如何使用 [=15 实现呢? =]
我知道我可以 dispatch
从我的 createAsyncThunk
函数中执行一个操作,但感觉不对并且有点违背函数本身的目的。此外,reducer 内部的副作用被认为是一种不好的做法。所以,我现在有点困惑,我想在应用程序的根目录中只有一个 Loader
组件,它在加载状态为真时被触发,而加载的内容并不重要
这是我当前代码的示例:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { AxiosError } from 'axios'
import { masterInstance } from 'api'
import { GetAccessCodeParams, RegistrationStateType } from 'store/slices/registration/types'
export const getAccessCodeRequest = createAsyncThunk<void, GetAccessCodeParams, { rejectValue: { message: string } }>(
'registration/getAccessCodeRequest',
async ({ email }, { rejectWithValue }) => {
try {
await masterInstance.post(`/authorization/getAccessCodeWc`, { email })
} catch (err) {
let error: AxiosError = err
if (error) {
return rejectWithValue({
message: `Error. Error code ${error.response?.status}`,
})
}
throw err
}
}
)
const initialState: RegistrationStateType = {
isLoading: false,
error: null,
}
const registrationSlice = createSlice({
name: 'registration',
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(getAccessCodeRequest.fulfilled, (state) => {
state.isLoading = false
state.error = null
})
builder.addCase(getAccessCodeRequest.pending, (state) => {
state.isLoading = true
state.error = null
})
builder.addCase(getAccessCodeRequest.rejected, (state, action) => {
if (action.payload) {
state.error = {
message: action.payload.message,
}
} else {
state.error = action.error
}
state.isLoading = false
})
},
})
export const registrationReducer = registrationSlice.reducer
我希望 isLoading
和 error
在一个单独的减速器中
你可以有一个共享的 reducer 匹配器函数。
// mySharedStuff.js
export const handleLoading = (action, (state) => {
state.loading = action.type.endsWith('/pending'); // or smth similar
});
export const handleError = (action, (state) => {
state.error = action.type.endsWith('/rejected'); // or smth similar
});
// mySlice.js
const mySlice = createSlice({
name: 'FOO',
initialState: {},
reducers: {},
extraReducers: builder => {
builder.addMatcher(handleLoading),
builder.addMatcher(handleError),
...
我正在开发一个有多个切片的应用程序。我将 createAsyncThunk
用于 API 调用,我喜欢它,因为它为 API 请求的不同状态提供了动作创建器,以便我可以跟踪加载状态和减速器中的错误。但我的问题是,如果我想有一个单独的减速器来跟踪我的 API 调用的 loading
、error
和 success
,我该如何使用 [=15 实现呢? =]
我知道我可以 dispatch
从我的 createAsyncThunk
函数中执行一个操作,但感觉不对并且有点违背函数本身的目的。此外,reducer 内部的副作用被认为是一种不好的做法。所以,我现在有点困惑,我想在应用程序的根目录中只有一个 Loader
组件,它在加载状态为真时被触发,而加载的内容并不重要
这是我当前代码的示例:
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import { AxiosError } from 'axios'
import { masterInstance } from 'api'
import { GetAccessCodeParams, RegistrationStateType } from 'store/slices/registration/types'
export const getAccessCodeRequest = createAsyncThunk<void, GetAccessCodeParams, { rejectValue: { message: string } }>(
'registration/getAccessCodeRequest',
async ({ email }, { rejectWithValue }) => {
try {
await masterInstance.post(`/authorization/getAccessCodeWc`, { email })
} catch (err) {
let error: AxiosError = err
if (error) {
return rejectWithValue({
message: `Error. Error code ${error.response?.status}`,
})
}
throw err
}
}
)
const initialState: RegistrationStateType = {
isLoading: false,
error: null,
}
const registrationSlice = createSlice({
name: 'registration',
initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(getAccessCodeRequest.fulfilled, (state) => {
state.isLoading = false
state.error = null
})
builder.addCase(getAccessCodeRequest.pending, (state) => {
state.isLoading = true
state.error = null
})
builder.addCase(getAccessCodeRequest.rejected, (state, action) => {
if (action.payload) {
state.error = {
message: action.payload.message,
}
} else {
state.error = action.error
}
state.isLoading = false
})
},
})
export const registrationReducer = registrationSlice.reducer
我希望 isLoading
和 error
在一个单独的减速器中
你可以有一个共享的 reducer 匹配器函数。
// mySharedStuff.js
export const handleLoading = (action, (state) => {
state.loading = action.type.endsWith('/pending'); // or smth similar
});
export const handleError = (action, (state) => {
state.error = action.type.endsWith('/rejected'); // or smth similar
});
// mySlice.js
const mySlice = createSlice({
name: 'FOO',
initialState: {},
reducers: {},
extraReducers: builder => {
builder.addMatcher(handleLoading),
builder.addMatcher(handleError),
...