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

