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

Redux Toolkit:是否需在useSelector中配合使用useCallback

关于useSelector与useCallback、proxy-memoize的疑问解答

1. 不使用proxy-memoize时,useSelector通常不需要配合useCallback

Redux的useSelector内部逻辑很明确:每次组件渲染时,它会调用传入的selector函数拿到结果,然后对当前结果和上一次的结果做浅比较——只要结果没变化,就不会触发组件重新渲染。

像你写的这种简单取值的selector:

const todo = useSelector((state) => state.todos[props.id])

虽然每次渲染时这个箭头函数都是新的引用,但useSelector根本不关心selector函数本身的引用是否变化,它只看返回值的浅比较结果。所以这种场景下,完全没必要套useCallback。

只有当你的selector涉及大量重复计算,或者依赖外部变量需要稳定缓存计算结果时,Redux官方推荐用createSelector(来自@reduxjs/toolkit或reselect)来创建记忆化的selector,而不是用useCallback包裹。

2. proxy-memoize要求配合useCallback的原因

proxy-memoize的核心是给selector函数添加结果缓存——它会记住之前传入的state和对应的返回值,当state中相关部分没变化时,直接返回缓存的结果,避免重复计算。

但问题在于:如果每次组件渲染都重新调用memoize(state => ({ … })),就会生成一个全新的带缓存的函数实例,之前积累的缓存会被直接丢弃,等于白做了记忆化优化。

这时候useCallback的作用就是固定memoize后的selector函数引用,保证每次渲染时传给useSelector的是同一个函数,这样proxy-memoize内部的缓存才能持续生效,真正起到减少重复计算的作用。

比如错误写法(缓存完全失效):

// 无效:每次渲染都重新生成memoized函数,缓存无法复用
useSelector(memoize(state => ({ todo: state.todos[props.id] })))

正确写法(缓存稳定生效):

// 有效:用useCallback固定函数引用,缓存能持续复用
useSelector(useCallback(memoize(state => ({ todo: state.todos[props.id] })), [props.id]))

这里还要加上[props.id]作为依赖数组,当props.id变化时,才重新生成memoized函数,保证selector能拿到最新的数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:48:11