React中setState用普通函数还是useCallback封装性能更优?
结论优先
在你给出的最简示例场景下,两种方案没有可感知的性能差异,盲目加useCallback反而属于过度优化。是否选用useCallback完全取决于你后续要不要把这个事件函数传给被React.memo包裹的自定义子组件。
两种方案的差异拆解
不使用
useCallback的方案:
每次App组件重渲染时,都会重新生成一个新的onCheckChange函数引用。但因为你是直接把函数传给原生input元素,原生DOM元素的事件处理不关心引用是否变化,不会触发额外的重渲染开销。唯一的成本是每次渲染创建新函数的开销,这个成本极低,完全可以忽略。
额外注意:这个写法的setChecked(!checked)依赖了外层的checked变量,如果后续你要给它套useCallback,必须把checked加入依赖数组,否则会出现闭包陷阱。使用
useCallback的方案:
你这里用了状态更新的函数式写法setChecked(prev => !prev),且setChecked的引用是React官方保证永远不变的,所以onCheckChange确实只会在组件首次渲染时创建一次,全程引用不变。但在你当前的示例中,这个优化没有任何实际收益,反而多了调用useCallback、依赖比对的微末开销,还让代码多了一层封装,可读性略有下降。
什么时候才应该用useCallback?
只有当同时满足以下两个条件时,useCallback的收益才会大于成本:
- 你要把这个函数作为props传给自定义子组件
- 这个自定义子组件被
React.memo包裹,用于避免不必要的重渲染
这种场景下,稳定的函数引用可以避免子组件因为props变化触发无意义的重渲染,尤其是子组件渲染成本很高(比如复杂的表单、列表项)的时候,优化收益会非常明显。
内容的提问来源于stack exchange,提问作者ineffable p

