为何使用useMemo后React子组件仍重渲染?React.memo默认不用的原因?
问题解答:React子组件重渲染与React.memo的疑问
一、为什么Child组件仍会重渲染?
React的默认渲染规则是:当父组件发生重渲染时,它的所有子组件都会无条件跟着重渲染,不管子组件接收的props有没有变化。
你用useMemo缓存了mPerson的引用,这确实保证了每次父组件重渲染时,传给Child和Mchild的person props引用是一致的,但Child组件没有做任何props对比优化——它不会检查前后props是否相同,只要父组件重渲染,它就会跟着执行渲染逻辑。
而Mchild被React.memo包裹后,React会自动对组件前后接收的props做浅比较:如果props的引用或值没有变化,就跳过子组件的重渲染。因为mPerson是useMemo缓存的,引用始终不变,所以Mchild不会重渲染。
二、React为何不默认采用React.memo的模式?
React的默认设计是在性能和开发体验之间做了平衡:
- 性能成本考量:
React.memo的浅比较本身需要消耗计算资源。对于大多数简单组件来说,直接重渲染的开销比做一次浅比较还要小,默认开启反而会拖慢整体应用性能。 - 避免过度优化:如果默认启用memo,开发者很容易陷入“为优化而优化”的误区,忽略真正的性能瓶颈。而且很多组件的props本来就需要频繁更新,memo根本起不到优化作用,反而白增加了比较成本。
- 符合直觉的默认行为:父组件更新则子组件更新,这个逻辑简单直观,降低了新手的理解成本。开发者可以根据实际性能需求,手动给需要优化的组件添加
React.memo,而不是强制所有组件都承担优化的额外成本。
三、始终使用React.memo的弊端
- 无意义的性能损耗:对于props频繁变化的组件,
React.memo的浅比较每次都会得出“props已变化”的结论,这时候比较的过程就是纯纯的额外开销,反而不如直接重渲染高效。 - 代码冗余与维护成本上升:每个组件都包裹
React.memo会让代码变得冗余,而且如果后续组件的props结构变化(比如新增了需要深层比较的属性),React.memo的浅比较可能会失效,增加排查问题的难度。 - 隐藏潜在bug:如果
useMemo/useCallback的依赖数组配置错误,导致缓存的props引用没有及时更新,React.memo会让组件跳过本该执行的重渲染,出现UI不更新的诡异问题,这种bug很难排查。
示例代码
import React, { useMemo, useState } from "react"; const Child = ({ person, which }: any) => { console.log(`${which} render`); return <div>{`From child component: ${person.first}`}</div>; }; const Mchild = React.memo(Child); function Parent() { console.log("Parent render"); const [message, setMessage] = useState<string>(""); const person = { first: "gary", last: "johnson" }; const mPerson = useMemo(() => person, []); return ( <div> <div> MESSAGE:{" "} <input value={message} onChange={(e) => setMessage(e.target.value)} /> </div> <div>Parent</div> <Child person={mPerson} which="Child" /> <Mchild person={mPerson} which="Mchild" /> </div> ); } export default Parent;
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

