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

为什么仅传递使用useCallback的prop时子组件仍会重渲染?

问题描述

我原本认为子组件仅在自身prop(numberModifier)变更时才会重渲染,而numberModifier使用了无依赖项的useCallback定义,因此不会发生变更。

为了验证这一点,我修改了Application组件内的“online”状态值,该值是Parent组件的入参prop,因此修改online时Application和Parent都会重渲染,这一表现符合预期。

但我发现Child组件也同步发生了重渲染,我无法理解该现象的原因:Child唯一的prop numberModifier并未发生任何变更。

请问为什么修改Application中的online值时,Child组件会触发重渲染?
如果这是React的正常表现,那么useCallback的实际作用是什么?

相关代码

function Application() {
 const [online, setOnline] = useState(true);

  return (
    <div>
    <button onClick={()=>setOnline(!online)}>Change Flag</button>
    <Parent online={online}/>
    </div>
  );
}
function Parent({online}) {
  const [number, setNumber] = useState(1);
  const numberModifier = useCallback(()=> {
    setNumber(69)
  },[])

  return (
    <>
    <p>Online is {online.toString()}</p>
    <p>Number is {number}</p>
    <Child numberModifier={numberModifier} />
    </>
  );
}
function Child({ numberModifier }) {
    return (
        <button onClick={numberModifier}>modify</button>
    );
}

以下是性能分析器的截图,显示Child组件重渲染的原因是其父组件发生了重渲染。注:绿色柱对应Child组件。
性能分析截图


解答

关于Child组件异常重渲染的原因

这是React的默认渲染逻辑,属于正常表现:只要父组件触发重渲染,其所有后代组件默认都会跟随重渲染,和子组件接收的props是否发生变化没有任何关系。
你所认为的「子组件仅在自身prop变更时重渲染」是手动优化后的效果,并非React的默认行为。当前你的Child组件没有做任何渲染优化配置,因此父组件Parent因为onlineprop更新触发重渲染时,Child自然会同步重渲染,和numberModifier是否变化无关。

如果要实现你预期的prop不变就跳过重渲染的效果,需要用React.memo高阶组件包裹Child组件,修改代码如下:

const Child = React.memo(({ numberModifier }) => {
    return (
        <button onClick={numberModifier}>modify</button>
    );
})

React.memo会在父组件重渲染时,对传入子组件的所有props做浅比较,只要所有props的引用和上一次渲染时完全一致,就会跳过当前子组件的重渲染流程。

useCallback的实际作用

useCallback的核心能力是缓存函数引用,只有当依赖项数组中的变量发生变化时,才会生成新的函数引用,它的适用场景主要有两类:

  1. 配合React.memo实现子组件渲染优化:如果没有用useCallback缓存numberModifier,那么每次Parent重渲染时都会生成一个全新的函数引用,哪怕给Child包了React.memo,也会因为prop的引用发生变化触发子组件重渲染,这种场景下useCallback是渲染优化链路中必不可少的一环。
  2. 避免依赖函数的副作用重复执行:如果把一个未缓存的函数作为useEffect、useMemo等钩子的依赖项,每次组件重渲染生成的新函数引用都会触发副作用重新执行,用useCallback缓存函数可以避免这类不必要的执行。

注意:如果没有配合React.memo做子组件渲染优化、也没有把函数作为其他钩子的依赖项,不需要额外使用useCallback,反而会增加不必要的性能开销。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 20:45:04