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

为何使用useMemo后子组件仍会在父组件状态变更时重新渲染?

问题原因与解决方案

核心原因

React中,父组件重渲染时,所有子组件默认都会跟着重渲染,不管子组件的props有没有变化。你用useMemo缓存了hitCounter的值,保证了传给子组件的props引用不变,但这只能确保props本身不变化,并没有阻止子组件因父组件重渲染而触发的重渲染——要实现props不变时子组件不重渲染,还需要给子组件加上React.memo优化。

代码里的额外问题

你的子组件代码还有两个明显错误:

  • 父组件传给子组件的props是hitCounter,但子组件的useEffect里监听的是props.counter,这个属性根本不存在,导致useEffect永远不会触发,data始终是初始值0;
  • 子组件没有用React.memo包裹,所以即使hitCounter没变化,父组件因clickCounter变化重渲染时,子组件也会跟着重渲染。

修正后的代码

import React, { useState, useMemo, useEffect, memo } from 'react';

const Parent = () => {
    let [hitCounter, setHitCounter] = useState(0);
    let [clickCounter, setClickCounter] = useState(0); 
    const data = useMemo(() => {
        console.log("in useMemo")
        return hitCounter
    },[hitCounter]);
    
    return(
        <>
            <Child hitCounter={data}/>
            <input type="button" onClick={() => setHitCounter(hitCounter + 1)} value="Hit me"/>
            {hitCounter}
            <div>
                <input type="button" onClick={() => setClickCounter(clickCounter + 1)} value="Click me"/>
                {clickCounter}
            </div>
        </>
    )
}

// 用React.memo包裹子组件,实现props浅比较优化
const Child = memo((props) => {
    let data = 0;
    useEffect(() => {
        console.log("in useeffect");
        // 修正props属性名,改为hitCounter
        data = props.hitCounter;
    },[props.hitCounter])
    console.log("in Child");
    return(
        <div>
            The Hit counter value is {data}
        </div>
    )
})

export default Parent;

原理说明

  1. useMemo:缓存hitCounter的值,确保hitCounter不变时,传给子组件的hitCounter props引用不会改变;
  2. React.memo:作为高阶组件,会对传入子组件的props进行浅比较。如果props没有变化,就会跳过子组件的重渲染,直接复用之前的渲染结果。

这样修改后,点击“Click me”按钮时,clickCounter变化导致父组件重渲染,但子组件的hitCounter props没有变化,子组件就不会再重渲染了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:40:27