跳至主要内容

createAction

用于定义 Redux action 类型和创建者的辅助函数。

function createAction(type, prepareAction?)

在 Redux 中,定义 action 的通常方法是分别声明一个action 类型常量和一个用于构造该类型 action 的action 创建者函数。

const INCREMENT = 'counter/increment'

function increment(amount: number) {
return {
type: INCREMENT,
payload: amount,
}
}

const action = increment(3)
// { type: 'counter/increment', payload: 3 }

createAction 辅助函数将这两个声明合并为一个。它接受一个 action 类型并返回该类型的 action 创建者。action 创建者可以不带参数调用,也可以带一个要附加到 action 的payload 调用。

import { createAction } from '@reduxjs/toolkit'

const increment = createAction<number | undefined>('counter/increment')

let action = increment()
// { type: 'counter/increment' }

action = increment(3)
// returns { type: 'counter/increment', payload: 3 }

console.log(`The action type is: ${increment.type}`)
// 'The action type is: counter/increment'

使用准备回调自定义 action 内容

默认情况下,生成的 action 创建者接受一个参数,该参数将成为action.payload。这要求调用者正确构造整个 payload 并将其传递进来。

在许多情况下,您可能希望编写额外的逻辑来自定义payload值的创建,例如接受 action 创建者的多个参数、生成随机 ID 或获取当前时间戳。为此,createAction 接受一个可选的第二个参数:“准备回调”,它将用于构造 payload 值。

import { createAction, nanoid } from '@reduxjs/toolkit'

const addTodo = createAction('todos/add', function prepare(text: string) {
return {
payload: {
text,
id: nanoid(),
createdAt: new Date().toISOString(),
},
}
})

console.log(addTodo('Write more docs'))
/**
* {
* type: 'todos/add',
* payload: {
* text: 'Write more docs',
* id: '4AJvwMSWEHCchcWYga3dj',
* createdAt: '2019-10-03T07:53:36.581Z'
* }
* }
**/

如果提供,action 创建者的所有参数都将传递给准备回调,它应该返回一个包含payload字段的对象(否则创建的 action 的 payload 将为undefined)。此外,该对象可以包含一个meta和/或一个error字段,它们也将添加到创建的 action 中。meta可能包含有关 action 的额外信息,error可能包含有关 action 失败的详细信息。这三个字段(payloadmetaerror)符合Flux Standard Actions的规范。

注意:类型字段将自动添加。

与 createReducer() 一起使用

action 创建者可以直接传递到createReducer()构建回调中的addCase中。

import { createAction, createReducer } from '@reduxjs/toolkit'

const increment = createAction<number>('counter/increment')
const decrement = createAction<number>('counter/decrement')

const counterReducer = createReducer(0, (builder) => {
builder.addCase(increment, (state, action) => state + action.payload)
builder.addCase(decrement, (state, action) => state - action.payload)
})
非字符串动作类型

从 Redux 5.0 开始,动作类型 *必须* 是字符串。如果非字符串动作类型到达原始商店调度,商店将抛出错误。

actionCreator.match

每个生成的 actionCreator 都有一个 .match(action) 方法,可用于确定传递的动作是否与 actionCreator 创建的动作类型相同。

这有不同的用途

作为 TypeScript 类型守卫

match 方法是 TypeScript 类型守卫,可用于区分动作的 payload 类型。

这种行为在自定义中间件中特别有用,否则可能需要手动转换。

import { createAction } from '@reduxjs/toolkit'
import type { Action } from '@reduxjs/toolkit'

const increment = createAction<number>('INCREMENT')

function someFunction(action: Action) {
// accessing action.payload would result in an error here
if (increment.match(action)) {
// action.payload can be used as `number` here
}
}

使用 redux-observable

match 方法也可以用作过滤方法,这使得它在与 redux-observable 一起使用时非常强大。

import { createAction } from '@reduxjs/toolkit'
import type { Action } from '@reduxjs/toolkit'
import type { Observable } from 'rxjs'
import { map, filter } from 'rxjs/operators'

const increment = createAction<number>('INCREMENT')

export const epic = (actions$: Observable<Action>) =>
actions$.pipe(
filter(increment.match),
map((action) => {
// action.payload can be safely used as number here (and will also be correctly inferred by TypeScript)
// ...
})
)