createAction
用於定義 Redux 動作類型和建立函式的輔助函式。
function createAction(type, prepareAction?)
在 Redux 中定義動作的常見做法是分別宣告一個動作類型常數和一個動作建立函式函式來建構該類型的動作。
- TypeScript
- JavaScript
const INCREMENT = 'counter/increment'
function increment(amount: number) {
return {
type: INCREMENT,
payload: amount,
}
}
const action = increment(3)
// { type: 'counter/increment', payload: 3 }
const INCREMENT = 'counter/increment'
function increment(amount) {
return {
type: INCREMENT,
payload: amount,
}
}
const action = increment(3)
// { type: 'counter/increment', payload: 3 }
createAction
輔助函式將這兩個宣告合併成一個。它會取得動作類型並傳回該類型的動作建立函式。動作建立函式可以不帶參數呼叫,或帶一個要附加到動作的payload
。
- TypeScript
- JavaScript
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'
import { createAction } from '@reduxjs/toolkit'
const increment = createAction('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.payload
。這需要呼叫者正確建構整個 payload 並傳入。
在很多情況下,您可能想要撰寫額外的邏輯來自訂建立 `payload` 值,例如接受動作建立器的多個參數、產生隨機 ID 或取得目前時間戳記。為此,`createAction` 接受一個選用的第二個引數:一個「準備回呼」,用於建構 `payload` 值。
- TypeScript
- JavaScript
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'
* }
* }
**/
import { createAction, nanoid } from '@reduxjs/toolkit'
const addTodo = createAction('todos/add', function prepare(text) {
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'
* }
* }
**/
如果已提供,動作建立器中的所有引數都將傳遞給準備回呼,且它應傳回一個具有 `payload` 欄位的物件(否則,已建立動作的 `payload` 將為 `undefined`)。此外,該物件可以具有 `meta` 和/或 `error` 欄位,它們也會新增到已建立的動作中。`meta` 可能包含動作的額外資訊,`error` 可能包含動作失敗的詳細資料。這三個欄位(`payload`、`meta` 和 `error`)遵守 Flux Standard Actions 的規範。
注意:類型欄位會自動新增。
與 createReducer() 搭配使用
動作建立器可以透過 createReducer() 建立回呼中的 `addCase` 直接傳遞。
- TypeScript
- JavaScript
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)
})
import { createAction, createReducer } from '@reduxjs/toolkit'
const increment = createAction('counter/increment')
const decrement = createAction('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
型別。
這種行為在自訂中間件中使用時特別有用,否則可能需要手動強制轉型。
- TypeScript
- JavaScript
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
}
}
import { createAction } from '@reduxjs/toolkit'
const increment = createAction('INCREMENT')
function someFunction(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 一起使用時非常強大
- TypeScript
- JavaScript
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)
// ...
})
)
import { createAction } from '@reduxjs/toolkit'
import { map, filter } from 'rxjs/operators'
const increment = createAction('INCREMENT')
export const epic = (actions$) =>
actions$.pipe(
filter(increment.match),
map((action) => {
// action.payload can be safely used as number here (and will also be correctly inferred by TypeScript)
// ...
})
)