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
ヘルパーは、これら2つの宣言を1つにまとめます。アクションタイプを受け取り、そのタイプのアクションクリエーターを返します。アクションクリエーターは、引数なしで、またはアクションに添付される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
になる単一の引数を受け入れます。これは、呼び出し側がペイロード全体を正しく構築して渡す必要があることを意味します。
多くの場合、アクションクリエーターに複数のパラメーターを受け入れる、ランダムIDを生成する、現在のタイムスタンプを取得するなど、payload
値の作成をカスタマイズするための追加ロジックを記述したい場合があります。これを行うために、createAction
はオプションの2番目の引数として、「準備コールバック」を受け入れます。これは、ペイロード値を構築するために使用されます。
- 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
フィールドを持つオブジェクトを返す必要があります(そうでない場合、作成されたアクションのペイロードはundefined
になります)。さらに、オブジェクトには、作成されたアクションにも追加されるmeta
フィールドまたはerror
フィールド、あるいはその両方を含めることができます。 meta
にはアクションに関する追加情報が含まれる場合があり、error
にはアクションの失敗に関する詳細が含まれる場合があります。これらの3つのフィールド(payload
、meta
、error
)は、Flux Standard Actionsの仕様に準拠しています。
注: typeフィールドは自動的に追加されます。
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
生成されたすべてのアクションクリエーターには、渡されたアクションがアクションクリエーターによって作成されるアクションと同じタイプであるかどうかを判断するために使用できる.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)
// ...
})
)