autoBatchEnhancer
一个 Redux 商店增强器,它会查找连续的一个或多个“低优先级”分派的 action,并将回调排队以延迟运行订阅者通知。然后,它会在排队的回调运行时或下一个“正常优先级”action 分派时通知订阅者,以先发生者为准。
基本用法
- 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 开始,autoBatchEnhancer
在调用 configureStore
时默认包含。
这意味着要配置它,你应该改为传递一个接收 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 store enhancer 实例。
任何带有 action.meta[SHOULD_AUTOBATCH] = true
标签的动作将被视为“低优先级”,并且通知回调将被排队。增强器将延迟通知订阅者,直到以下情况之一发生:
- 排队的回调运行并触发通知
- 一个“正常优先级”动作(任何没有
action.meta[SHOULD_AUTOBATCH] = true
的动作)在同一 tick 中被分派
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 动作/调度" 方法。
- 一个高阶 reducer,它接受嵌套在一个真实动作中的多个动作,并一起遍历它们。
- 一个增强器,它包装
dispatch
并对通知回调进行去抖动。 - 一个增强器,它包装
dispatch
以接受一个动作数组。 - React 的
unstable_batchedUpdates()
,它只是将多个排队的渲染合并为一个,但不会影响订阅者通知。
此增强器是 "去抖动" 方法的变体,但带有一个变化。
它不是仅仅对所有订阅者通知进行去抖动,而是监视任何带有特定 action.meta[SHOULD_AUTOBATCH]: true
字段的附加动作。
当它看到带有该字段的动作时,它会排队一个回调。reducer 会立即更新,但增强器不会立即通知订阅者。如果其他带有相同字段的动作连续调度,增强器将继续不通知订阅者。然后,当排队的回调运行时,它最终会通知所有订阅者,类似于 React 如何批处理重新渲染。
额外的变化也受到 React 将更新分为 "低优先级" 和 "立即" 行为的启发(例如,由 AJAX 请求排队的渲染与由用户输入排队的渲染,该渲染应该同步处理)。
如果一些低优先级动作已被调度并且已排队通知微任务,然后调度了一个正常优先级动作(没有该字段),增强器将继续像往常一样同步通知所有订阅者,并且不会在滴答结束时通知它们。
这允许 Redux 用户选择性地标记某些动作以实现有效的批处理行为,使其成为纯粹的按动作选择加入,同时保留所有其他动作的正常通知行为。
RTK Query 和批处理
RTK Query 已经将几个关键的内部动作类型标记为可批处理的。通过将 autoBatchEnhancer
添加到存储设置中,它可以提高整体 UI 性能,尤其是在渲染使用 RTKQ 查询钩子的大量组件列表时。