跳到主要內容

比對工具

Redux Toolkit 匯出多種類型安全的動作比對工具,當您檢查特定類型的動作時,您可以利用這些工具。這些工具主要用於 createSlicecreateReducer 中的 builder.addMatcher() 案例,以及編寫自訂 Middleware 時。

一般用途

  • isAllOf - 當所有條件都符合時回傳 true
  • isAnyOf - 當至少一個條件符合時回傳 true

createAsyncThunk 專用比對器

所有這些比對器都可以使用一個或多個 thunk 作為引數來呼叫,這種情況下,它們會回傳該條件和 thunk 的比對器函式,或使用一個動作,這種情況下,它們會比對具有該條件的任何 thunk 動作。

  • isAsyncThunkAction - 接受一個或多個動作建立器,並在所有比對都符合時回傳 true
  • isPending - 接受一個或多個動作建立器,並在所有比對都符合時回傳 true
  • isFulfilled - 接受一個或多個動作建立器,並在所有比對都符合時回傳 true
  • isRejected - 接受一個或多個動作建立器,並在所有比對都符合時回傳 true
  • isRejectedWithValue - 接受一個或多個動作建立器,並在所有比對都符合時回傳 true

isAllOf

接受一個或多個以下項目的高階函式

  • redux-toolkit 動作建立器函式,例如由下列函式產生的函式
  • 類型防護函式
  • 具有 .match 屬性的自訂動作建立器函式,該屬性為類型防護

它將回傳一個類型防護函式,如果所有提供的函式都符合,則回傳 true

isAnyOf

接受與 isAllOf 相同的輸入,並將回傳一個類型防護函式,如果至少一個提供的函式符合,則回傳 true

isAsyncThunkAction

回傳類型防護函式的高階函式,可用於檢查動作是否由 createAsyncThunk 建立。

isAsyncThunkAction 用法
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)) {
// action is an action dispatched by either `requestThunk1` or `requestThunk2`
}
}

isPending

回傳類型防護函式的高階函式,可用於檢查動作是否為來自 createAsyncThunk 承諾生命週期的「待處理」動作建立器。

isPending 用法
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)) {
// action is a pending action dispatched by either `requestThunk1` or `requestThunk2`
}
}

isFulfilled

回傳類型防護函式的高階函式,可用於檢查動作是否為來自 createAsyncThunk 承諾生命週期的「已完成」動作建立器。

isFulfilled 用法
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)) {
// action is a fulfilled action dispatched by either `requestThunk1` or `requestThunk2`
}
}

isRejected

高階函式,回傳類型防護函式,可用於檢查動作是否為 createAsyncThunk 承諾生命週期中的「已拒絕」動作建立器。

isRejected 用法
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)) {
// action is a rejected action dispatched by either `requestThunk1` or `requestThunk2`
}
}

isRejectedWithValue

高階函式,回傳類型防護函式,可用於檢查動作是否為 createAsyncThunk 承諾生命週期中,由 rejectWithValue 建立的「已拒絕」動作建立器。

isRejectedWithValue 用法
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)) {
// action is a rejected action dispatched by either `requestThunk1` or `requestThunk2`
// where rejectWithValue was used
}
}

使用比對器減少程式碼複雜度、重複和樣板程式碼

使用 builder 模式建構簡化器時,我們一次新增一個案例或比對器。然而,透過使用 isAnyOfisAllOf,我們能夠輕鬆地以類型安全的方式,將同一個比對器用於多個案例。

首先,我們來檢視一個不必要的複雜範例

不使用比對器工具的範例
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,
}
}
)

// This has unnecessary complexity
const loadingReducer = createReducer(initialState, (builder) => {
builder.addCase(isSpecialAndInterestingThunk.fulfilled, (state, action) => {
if (isSpecial(action)) {
state.isSpecial = true
}
if (isInteresting(action)) {
state.isInteresting = true
}
})
})

在這個情況下,我們可以使用 isAllOf 簡化我們的程式碼,並減少一些樣板程式碼。

使用 isAllOf 重構
import { createReducer, isAllOf } from '@reduxjs/toolkit'
import {
isSpecialAndInterestingThunk,
initialState,
isSpecial,
isInteresting,
} from '@virtual/matchers' // This is a fake pkg that provides the types shown above
import type { Data } from '@virtual/matchers' // This is a fake pkg that provides the types shown above

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 類型防護

isAllOfisAnyOf 回傳的函式,也可以在其他內容中用作 TypeScript 類型防護。

將 isAllOf 用作類型防護
import { isAllOf } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import { isSpecial, isInteresting } from '@virtual/matchers' // This is a fake pkg that provides the types shown above
import type { Data } from '@virtual/matchers' // This is a fake pkg that provides the types shown above

const isSpecialAndInteresting = isAllOf(isSpecial, isInteresting)

function someFunction(action: PayloadAction<Data>) {
if (isSpecialAndInteresting(action)) {
// "action" will be correctly typed as:
// `PayloadAction<Special> & PayloadAction<Interesting>`
}
}
將 isAnyOf 用作類型防護
import { isAnyOf } from '@reduxjs/toolkit'
import type { PayloadAction } from '@reduxjs/toolkit'
import { Data, isSpecial, isInteresting } from '@virtual/matchers' // this is a fake pkg that provides the types shown above

const isSpecialOrInteresting = isAnyOf(isSpecial, isInteresting)

function someFunction(action: PayloadAction<Data>) {
if (isSpecialOrInteresting(action)) {
// "action" will be correctly typed as:
// `PayloadAction<Special> | PayloadAction<Interesting>`
}
}

範例