メインコンテンツへスキップ

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ヘルパーは、これら2つの宣言を1つにまとめます。アクションタイプを受け取り、そのタイプのアクションクリエーターを返します。アクションクリエーターは、引数なしで、またはアクションに添付される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.payloadになる単一の引数を受け入れます。これは、呼び出し側がペイロード全体を正しく構築して渡す必要があることを意味します。

多くの場合、アクションクリエーターに複数のパラメーターを受け入れる、ランダムIDを生成する、現在のタイムスタンプを取得するなど、payload値の作成をカスタマイズするための追加ロジックを記述したい場合があります。これを行うために、createActionはオプションの2番目の引数として、「準備コールバック」を受け入れます。これは、ペイロード値を構築するために使用されます。

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

指定されている場合、アクションクリエーターからのすべての引数が準備コールバックに渡され、payloadフィールドを持つオブジェクトを返す必要があります(そうでない場合、作成されたアクションのペイロードはundefinedになります)。さらに、オブジェクトには、作成されたアクションにも追加されるmetaフィールドまたはerrorフィールド、あるいはその両方を含めることができます。 metaにはアクションに関する追加情報が含まれる場合があり、errorにはアクションの失敗に関する詳細が含まれる場合があります。これらの3つのフィールド(payloadmetaerror)は、Flux Standard Actionsの仕様に準拠しています。

注: typeフィールドは自動的に追加されます。

createReducer()での使用

アクションクリエーターは、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

生成されたすべてのアクションクリエーターには、渡されたアクションがアクションクリエーターによって作成されるアクションと同じタイプであるかどうかを判断するために使用できる.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) {
// 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)
// ...
})
)