跳至主要内容

autoBatchEnhancer

一个 Redux 商店增强器,它会查找连续的一个或多个“低优先级”分派的 action,并将回调排队以延迟运行订阅者通知。然后,它会在排队的回调运行时或下一个“正常优先级”action 分派时通知订阅者,以先发生者为准。

基本用法

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,
})

API

autoBatchEnhancer

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 并用你想要的设置调用它的回调函数。

使用 getDefaultEnhancers 配置 autoBatchEnhancer
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

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 查询钩子的大量组件列表时。