跳到主要内容

 

createAction

这是一个用于定义 Redux 动作类型和创建器的辅助函数。

function createAction(type, prepareAction?)

在 Redux 中定义动作的常规方式是分别声明一个 动作类型 常量和一个用于构造该类型动作的 动作创建器 函数。

const INCREMENT = 'counter/increment'

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

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

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

import { createAction } from '@reduxjs/toolkit'

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

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

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

console.log(`动作类型是:${increment.type}`)
// '动作类型是:counter/increment'

使用 Prepare 回调自定义动作内容

默认情况下,生成的动作创建器接受一个参数,该参数成为 action.payload。这要求调用者正确构造整个有效载荷并传入。

在许多情况下,你可能希望编写额外的逻辑来自定义 payload 值的创建,例如接受动作创建器的多个参数,生成随机 ID,或获取当前时间戳。为此,createAction 接受一个可选的第二个参数:一个将用于构造有效载荷值的 "prepare callback"。

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'
* }
* }
**/

如果提供了,动作创建器的所有参数都将传递给 prepare 回调,它应返回一个带有 payload 字段的对象(否则创建的动作的有效载荷将为 undefined)。此外,该对象可以有一个 meta 和/或一个 error 字段,也将添加到创建的动作中。meta 可能包含关于动作的额外信息,error 可能包含关于动作失败的详细信息。这三个字段(payloadmetaerror)遵循 Flux Standard Actions 的规范。

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

与 createReducer() 的使用

动作创建器可以直接传递给 addCasecreateReducer() 构建回调中。

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) 方法,可以用来确定传递的动作是否与由动作创建器创建的动作的类型相同。

这有不同的用途:

作为 TypeScript 类型保护

这个 match 方法是一个 TypeScript 类型保护,可以用来区分动作的 payload 类型。

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

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

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

function someFunction(action: Action) {
// 在这里访问 action.payload 将导致错误
if (increment.match(action)) {
// 在这里,action.payload 可以作为 `number` 使用
}
}

与 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 可以安全地用作数字(并且也会被 TypeScript 正确推断)
// ...
}),
)