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
相关产品推荐
相关产品推荐

