You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Redux Toolkit中createSelector与createDraftSafeSelector API的区别是什么?

createSelector 与 createDraftSafeSelector 核心区别及适用场景

注:createSelector 是reselect库提供的基础记忆化选择器API,createDraftSafeSelector是Redux Toolkit对前者的增强封装,专门适配RTK基于Immer的reducer开发模式。

核心区别

二者本质上都是用于生成带缓存能力的衍生数据计算工具,唯一核心差异是对Immer Draft对象的兼容性处理:

  • createSelector:仅对普通不可变state对象做缓存判断,传入Immer生成的Draft对象时会出现缓存失效、计算结果错误的问题,无法在reducer内部使用。
  • createDraftSafeSelector:会自动识别传入的参数类型:传入普通state时和createSelector表现完全一致,正常走缓存逻辑;传入Immer Draft时会跳过缓存直接重新计算,避免运行异常。

示例说明

首先定义两个不同版本的选择器:

// 基础输入选择器
const selectUser = state => state.user

// 普通版选择器
const selectUserAge = createSelector(
  [selectUser],
  user => user.age
)

// Draft安全版选择器
const selectDraftSafeUserAge = createDraftSafeSelector(
  [selectUser],
  user => user.age
)

场景1:组件内获取普通state(二者表现一致)

组件中通过useSelector拿到的都是不可变的普通state,此时两个选择器都会正常缓存,只有当state.user发生引用变化时才会重新计算年龄:

// 组件内使用
const age = useSelector(selectUserAge)
const draftSafeAge = useSelector(selectDraftSafeUserAge)
// 二者返回值完全相同,缓存逻辑也完全一致

场景2:reducer内操作Immer Draft(仅后者可用)

在createSlice/createReducer的reducer回调中,我们拿到的state是Immer生成的可修改Draft对象,此时用普通的createSelector就会出现异常:

const userSlice = createSlice({
  name: 'user',
  initialState: { age: 18, name: '张三' },
  reducers: {
    addAge: (state) => {
      // ❌ 错误写法:传入Immer Draft,普通选择器会返回错误的缓存结果甚至直接报错
      // const age = selectUserAge(state)

      // ✅ 正确写法:使用Draft安全的选择器可以正常拿到正确结果
      const age = selectDraftSafeUserAge(state)
      state.age = age + 1
    }
  }
})

适用场景

  • 仅在组件、自定义Hook中通过useSelector获取衍生数据:直接使用createSelector即可,无额外性能开销。
  • 选择器需要在reducer内部调用、或者存在传入Immer Draft对象的使用场景:必须使用createDraftSafeSelector保证运行正确性。

内容的提问来源于stack exchange,提问作者Alok

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:15:04