autoBatchEnhancer
連続する1つ以上の「低優先度」ディスパッチアクションを検出し、遅延してサブスクライバー通知を実行するコールバックをキューに入れるReduxストアエンハンサー。次に、キューに入れられたコールバックが実行されるか、次の「通常優先度」アクションがディスパッチされるかのいずれか早い方のタイミングで、サブスクライバーに通知します。
基本的な使用方法
- TypeScript
- JavaScript
import {
createSlice,
configureStore,
autoBatchEnhancer,
prepareAutoBatched,
} from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 } satisfies CounterState as CounterState,
reducers: {
incrementBatched: {
// Batched, low-priority
reducer(state) {
state.value += 1
},
// Use the `prepareAutoBatched` utility to automatically
// add the `action.meta[SHOULD_AUTOBATCH]` field the enhancer needs
prepare: prepareAutoBatched<void>(),
},
// Not batched, normal priority
decrementUnbatched(state) {
state.value -= 1
},
},
})
const { incrementBatched, decrementUnbatched } = counterSlice.actions
// includes batch enhancer by default, as of RTK 2.0
const store = configureStore({
reducer: counterSlice.reducer,
})
import {
createSlice,
configureStore,
prepareAutoBatched,
} from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
incrementBatched: {
// Batched, low-priority
reducer(state) {
state.value += 1
},
// Use the `prepareAutoBatched` utility to automatically
// add the `action.meta[SHOULD_AUTOBATCH]` field the enhancer needs
prepare: prepareAutoBatched(),
},
// Not batched, normal priority
decrementUnbatched(state) {
state.value -= 1
},
},
})
const { incrementBatched, decrementUnbatched } = counterSlice.actions
// includes batch enhancer by default, as of RTK 2.0
const store = configureStore({
reducer: counterSlice.reducer,
})
API
autoBatchEnhancer
export type SHOULD_AUTOBATCH = string
type AutoBatchOptions =
| { type: 'tick' }
| { type: 'timer'; timeout: number }
| { type: 'raf' }
| { type: 'callback'; queueNotification: (notify: () => void) => void }
export type autoBatchEnhancer = (options?: AutoBatchOptions) => StoreEnhancer
RTK 2.0 以降、configureStore
を呼び出すと、デフォルトで autoBatchEnhancer
が含まれています。
これは、設定するには、代わりに getDefaultEnhancers
を受け取り、目的の設定でそれを呼び出すコールバックを渡す必要があることを意味します。
- TypeScript
- JavaScript
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({
reducer: () => 0,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({
autoBatch: { type: 'tick' },
}),
})
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({
reducer: () => 0,
enhancers: (getDefaultEnhancers) =>
getDefaultEnhancers({
autoBatch: { type: 'tick' },
}),
})
autobatch ストアエンハンサーの新しいインスタンスを作成します。
action.meta[SHOULD_AUTOBATCH] = true
でタグ付けされたアクションは「低優先度」として扱われ、通知コールバックがキューに入れられます。エンハンサーは、次のいずれかの条件が満たされるまで、サブスクライバーへの通知を遅延します。
- キューに入れられたコールバックが実行され、通知がトリガーされる
- 同じティックで「通常優先度」アクション(
action.meta[SHOULD_AUTOBATCH] = true
*のない*アクション)がディスパッチされる
autoBatchEnhancer
は、通知コールバックのキューイング方法を設定するためのオプションを受け入れます。
{type: 'raf'}
:requestAnimationFrame
を使用してキューに入れる(デフォルト){type: 'tick'}
:queueMicrotask
を使用してキューに入れる{type: 'timer', timeout: number}
:setTimeout
を使用してキューに入れる{type: 'callback', queueNotification: (notify: () => void) => void}
:デバウンスまたはスロットルされた関数など、独自のコールバックを提供できるようにします
デフォルトの動作は、requestAnimationFrame
を使用して通知をキューに入れることです。
SHOULD_AUTOBATCH
値は不透明であることを意図しています。現在は簡単にするために文字列ですが、将来的には Symbol
になる可能性があります。
prepareAutoBatched
type prepareAutoBatched = <T>() => (payload: T) => { payload: T; meta: unknown }
payload
値を受け取り、{payload, meta: {[SHOULD_AUTOBATCH]: true}}
を持つオブジェクトを返す関数を作成します。これは、RTK の createSlice
とその「prepare
コールバック」構文で使用することを意図しています。
createSlice({
name: 'todos',
initialState,
reducers: {
todoAdded: {
reducer(state, action: PayloadAction<Todo>) {
state.push(action.payload)
},
prepare: prepareAutoBatched<Todo>(),
},
},
})
バッチ処理のアプローチと背景
投稿 Redux バッチ処理技術の比較 では、「Redux アクション/ディスパッチのバッチ処理」のための 4 つの異なるアプローチについて説明しています。
- 1 つの実アクション内にネストされた複数のアクションを受け取り、それらをまとめて反復処理する高階 reducer
dispatch
をラップし、通知コールバックをデバウンスするエンハンサー- アクションの配列を受け入れるために
dispatch
をラップするエンハンサー - React の
unstable_batchedUpdates()
。これは、複数のキューに入れられたレンダリングを 1 つに結合するだけですが、サブスクライバー通知には影響しません。
このエンハンサーは「デバウンス」アプローチのバリエーションですが、ひねりが加えられています。
*すべて*のサブスクライバー通知をデバウンスする*だけ*ではなく、特定の action.meta[SHOULD_AUTOBATCH]: true
フィールドがアタッチされたアクションを監視します.
そのフィールドを持つアクションが表示されると、コールバックをキューに入れます。reducer はすぐに更新されますが、エンハンサーはすぐにサブスクライバーに通知*しません*。同じフィールドを持つ他のアクションが連続してディスパッチされた場合、エンハンサーは引き続きサブスクライバーに通知*しません*。次に、キューに入れられたコールバックが実行されると、React が再レンダリングをバッチ処理する方法と同様に、最終的にすべてのサブスクライバーに通知します.
追加のひねりは、React が更新を「低優先度」と「即時」の動作(AJAX リクエストによってキューに入れられたレンダリングと、同期的に処理する必要があるユーザー入力によってキューに入れられたレンダリングなど)に分けていることからも着想を得ています。
いくつかの低優先度アクションがディスパッチされ、通知マイクロタスクがキューに入れられた後、*通常*優先度のアクション(フィールドなし)がディスパッチされた場合、エンハンサーは通常どおり同期的にすべてのサブスクライバーに通知し、ティックの終わりに通知*しません*。
これにより、Redux ユーザーは特定のアクションを選択的にタグ付けして効果的なバッチ処理動作を実現し、他のすべてのアクションの通常の通知動作を維持しながら、アクションごとに完全にオプトインすることができます。
RTK Query とバッチ処理
RTK Query は、すでにいくつかの主要な内部アクションタイプをバッチ処理可能としてマークしています。ストアのセットアップに autoBatchEnhancer
を追加することで、特に RTKQ クエリフックを使用するコンポーネントの大きなリストをレンダリングする場合に、UI の全体的なパフォーマンスが向上します。