匹配工具
Redux Toolkit 导出了几个类型安全的动作匹配工具,你可以在检查特定类型的动作时使用它们。这些主要用于 createSlice
和 createReducer
中的 builder.addMatcher()
情况,以及编写自定义中间件时。
通用目的
createAsyncThunk
-特定匹配器
所有这些匹配器都可以用一个或多个 thunk 作为参数调用,在这种情况下,它们将返回一个匹配器函数,用于该条件和 thunk,或者用一个动作调用,在这种情况下,它们将匹配任何具有所述条件的 thunk 动作。
isAsyncThunkAction
- 接受一个或多个动作创建器并在所有匹配时返回 trueisPending
- 接受一个或多个动作创建器并在所有匹配时返回 trueisFulfilled
- 接受一个或多个动作创建器并在所有匹配时返回 trueisRejected
- 接受一个或多个动作创建器并在所有匹配时返回 trueisRejectedWithValue
- 接受一个或多个动作创建器并在所有匹配时返回 true
isAllOf
一个高阶函数,接受一个或多个:
redux-toolkit
动作创建函数,例如由以下产生的:- 类型保护函数
- 自定义动作创建函数,具有
.match
属性,该属性是类型保护
它将返回一个类型保护函数,如果提供的所有函数都匹配,则返回 true
。
isAnyOf
接受与 isAllOf
相同的输入,并将返回一个类型保护函数,如果至少有一个提供的函数匹配,则返回 true
。
isAsyncThunkAction
一个高阶函数,返回一个类型保护函数,可以用来检查一个动作是否由 createAsyncThunk
创建。
import { isAsyncThunkAction } from '@reduxjs/toolkit'
import type { UnknownAction } from '@reduxjs/toolkit'
import { requestThunk1, requestThunk2 } from '@virtual/matchers'
const isARequestAction = isAsyncThunkAction(requestThunk1, requestThunk2)
function handleRequestAction(action: UnknownAction) {
if (isARequestAction(action)) {
// 动作是由 `requestThunk1` 或 `requestThunk2` 分派的动作
}
}
isPending
一个高阶函 数,返回一个类型保护函数,可以用来检查一个动作是否是 createAsyncThunk
promise 生命周期中的 'pending' 动作创建器。
import { isPending } from '@reduxjs/toolkit'
import type { UnknownAction } from '@reduxjs/toolkit'
import { requestThunk1, requestThunk2 } from '@virtual/matchers'
const isAPendingAction = isPending(requestThunk1, requestThunk2)
function handlePendingAction(action: UnknownAction) {
if (isAPendingAction(action)) {
// 动作是由 `requestThunk1` 或 `requestThunk2` 分派的 pending 动作
}
}
isFulfilled
一个高阶函数,返回一个类型保护函数,可以用来检查一个动作是否是 createAsyncThunk
promise 生命周期中的 'fulfilled' 动作创建器。
import { isFulfilled } from '@reduxjs/toolkit'
import type { UnknownAction } from '@reduxjs/toolkit'
import { requestThunk1, requestThunk2 } from '@virtual/matchers'
const isAFulfilledAction = isFulfilled(requestThunk1, requestThunk2)
function handleFulfilledAction(action: UnknownAction) {
if (isAFulfilledAction(action)) {
// 动作是由 `requestThunk1` 或 `requestThunk2` 分派的 fulfilled 动作
}
}
isRejected
一个高阶函数,返回一个类型保护函数,可以用来检查一个动作是否是 createAsyncThunk
promise 生命周期中的 'rejected' 动作创建器。
import { isRejected } from '@reduxjs/toolkit'
import type { UnknownAction } from '@reduxjs/toolkit'
import { requestThunk1, requestThunk2 } from '@virtual/matchers'
const isARejectedAction = isRejected(requestThunk1, requestThunk2)
function handleRejectedAction(action: UnknownAction) {
if (isARejectedAction(action)) {
// 动作是由 `requestThunk1` 或 `requestThunk2` 分派的 rejected 动作
}
}
isRejectedWithValue
一个高阶函数,返回一个类型保护函数,可以用来检查一个动作是否是 createAsyncThunk
promise 生命周期中的 'rejected' 动作创建器,该动作是由 rejectWithValue
创建的。
import { isRejectedWithValue } from '@reduxjs/toolkit'
import type { UnknownAction } from '@reduxjs/toolkit'
import { requestThunk1, requestThunk2 } from '@virtual/matchers'
const isARejectedWithValueAction = isRejectedWithValue(
requestThunk1,
requestThunk2,
)
function handleRejectedWithValueAction(action: UnknownAction) {
if (isARejectedWithValueAction(action)) {
// 动作是由 `requestThunk1` 或 `requestThunk2` 分派的 rejected 动作
// rejectWithValue 被使用
}
}
使用匹配器减少代码复杂性、重复和样板代码
当使用 builder
模式构建一个 reducer 时,我们一次添加一个 case 或匹配器。然而,通过使用 isAnyOf
或 isAllOf
,我们能够以类型安全的方式轻松地为多个 case 使用相同的匹配器。
首先,让我们看一个不必要复杂的例子:
import { createAsyncThunk, createReducer } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
interface Data {
isInteresting: boolean
isSpecial: boolean
}
interface Special extends Data {
isSpecial: true
}
interface Interesting extends Data {
isInteresting: true
}
function isSpecial(
action: PayloadAction<Data>,
): action is PayloadAction<Special> {
return action.payload.isSpecial
}
function isInteresting(
action: PayloadAction<Data>,
): action is PayloadAction<Interesting> {
return action.payload.isInteresting
}
interface ExampleState {
isSpecial: boolean
isInteresting: boolean
}
const initialState = {
isSpecial: false,
isInteresting: false,
} satisfies ExampleState as ExampleState
export const isSpecialAndInterestingThunk = createAsyncThunk(
'isSpecialAndInterestingThunk',
() => {
return {
isSpecial: true,
isInteresting: true,
}
},
)
// 这里有不必要的复杂性
const loadingReducer = createReducer(initialState, (builder) => {
builder.addCase(isSpecialAndInterestingThunk.fulfilled, (state, action) => {
if (isSpecial(action)) {
state.isSpecial = true
}
if (isInteresting(action)) {
state.isInteresting = true
}
})
})
在这种情况下,我们可以使用 isAllOf
来简化我们的代码并减少一些样板代码。
import { createReducer, isAllOf } from '@reduxjs/toolkit'
import {
isSpecialAndInterestingThunk,
initialState,
isSpecial,
isInteresting,
} from '@virtual/matchers' // 这是一个提供上述类型的虚构包
import type { Data } from '@virtual/matchers' // 这是一个提供上述类型的虚构包
const loadingReducer = createReducer(initialState, (builder) => {
builder
.addMatcher(
isAllOf(isSpecialAndInterestingThunk.fulfilled, isSpecial),
(state, action) => {
state.isSpecial = true
},
)
.addMatcher(
isAllOf(isSpecialAndInterestingThunk.fulfilled, isInteresting),
(state, action) => {
state.isInteresting = true
},
)
})
将匹配器用作 TypeScript 类型保护
由 isAllOf
和 isAnyOf
返回的函数也可以在其他上下文中用作 TypeScript 类型保护。
import { isAllOf } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import { isSpecial, isInteresting } from '@virtual/matchers' // 这是一个提供上述类型的虚构包
import type { Data } from '@virtual/matchers' // 这是一个提供上述类型的虚构包
const isSpecialAndInteresting = isAllOf(isSpecial, isInteresting)
function someFunction(action: PayloadAction<Data>) {
if (isSpecialAndInteresting(action)) {
// "action" 将被正确地类型化为:
// `PayloadAction<Special> & PayloadAction<Interesting>`
}
}
import { isAnyOf } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import { Data, isSpecial, isInteresting } from '@virtual/matchers' // 这是一个提供上述类型的虚构包
const isSpecialOrInteresting = isAnyOf(isSpecial, isInteresting)
function someFunction(action: PayloadAction<Data>) {
if (isSpecialOrInteresting(action)) {
// "action" 将被正确地类型化为:
// `PayloadAction<Special> | PayloadAction<Interesting>`
}
}