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

React自定义Hook重渲染时函数会重建吗?useCallback/useMemo可用吗

React自定义Hook函数缓存问题解答

重渲染时自定义Hook内部的函数会重建吗?

会。
自定义Hook本质是和组件渲染周期绑定的普通函数,每次宿主组件触发重渲染,对应的自定义Hook就会从头完整执行一遍,内部声明的refresh、onClick这类函数都会在内存中生成全新的引用,和上一轮渲染生成的函数不是同一个对象。

顺带提一句,你贴的示例代码有两个笔误:一是useController定义时缺少赋值箭头,正确写法是const useController = () => {;二是返回值和组件解构时写的resfresh是拼写错误,正确应为refresh,否则代码运行时会拿不到对应方法。

有优化需求时可以用useCallback/useMemo包裹这些函数吗?

可以,但必须先明确优化的收益场景,绝对不要无脑包裹——你看到的「错误使用useMemo/useCallback反而带来更高性能开销」的结论是完全成立的:这两个API本身会产生依赖收集、缓存比对的固定成本,在没有明确收益的场景下使用,开销确实比直接重新创建函数更高。

只有在以下两类场景下,包裹才是划算的:

  • 你把这些函数作为props传递给了被React.memo包裹的子组件,稳定的函数引用可以避免子组件触发非必要的重渲染
  • 这些函数本身会被其他Hook(比如useEffect、useMemo)列为依赖项,稳定的引用可以避免这些Hook非必要的重复执行

推荐的优化写法

针对你示例里的自定义Hook,更推荐用函数式状态更新的写法消除外部依赖,这样既可以保证函数引用长期稳定,也不需要在依赖数组里声明状态值,减少缓存失效的概率:

const useController = () => {
  const [click, setClick] = useState(0)
  // 无外部依赖,引用全程稳定
  const refresh = useCallback(() => {
    setClick(0)
  }, [])
  // 用函数式更新读取上一个状态,不需要依赖click变量
  const onClick = useCallback(() => {
    setClick(prev => prev + 1)
  }, [])

  return {
    click, onClick, refresh
  }
}

几个不要踩的坑

  • 不要给所有Hook内的函数无脑套useCallback:如果函数只在当前组件的原生事件绑定中使用,也没有传递给memo化的子组件,直接创建新函数的开销远小于useCallback的缓存比对开销,完全没必要包裹
  • 不要随意给Hook返回的整个对象套useMemo:除非你明确所有消费方都需要整个对象的引用稳定,否则只会徒增依赖维护成本,很容易因为漏写依赖触发闭包陷阱,拿到过期的状态或方法
  • 不要为了消除ESLint的依赖警告随意篡改依赖数组,否则闭包问题导致的状态异常排查成本远高于优化带来的收益

内容的提问来源于stack exchange,提问作者Victor Harlan Lacson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:27:29