为何使用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;
原理说明
useMemo:缓存hitCounter的值,确保hitCounter不变时,传给子组件的hitCounterprops引用不会改变;React.memo:作为高阶组件,会对传入子组件的props进行浅比较。如果props没有变化,就会跳过子组件的重渲染,直接复用之前的渲染结果。
这样修改后,点击“Click me”按钮时,clickCounter变化导致父组件重渲染,但子组件的hitCounter props没有变化,子组件就不会再重渲染了。
内容的提问来源于stack exchange,提问作者Aditya yadav
相关产品推荐
相关产品推荐

