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

React.memo失效问题排查:如何正确缓存子组件的子组件?

问题分析与解决方案

你遇到的核心问题确实和Icon属性的传递方式有关——每次ToolbarComponent重新渲染时,你都在创建一个全新的<MyOtherIcon /> JSX元素实例,这就导致即使React.memo里的比较函数检查icon是否相等,也会因为前后两个icon是不同的对象引用而返回false,最终触发ToolbarButton的重渲染。

让我们拆解一下原因:

  • 当CIsTrue状态变化时,App会重新渲染,进而导致ToolbarComponent重新渲染
  • 在ToolbarComponent的渲染过程中,<MyOtherIcon />会被重新创建为一个新的React元素对象(哪怕它的逻辑完全没变)
  • 这个新的icon属性传递给ToolbarButton时,和之前的icon引用不相等,你的比较函数就会认为props变化了,于是触发重渲染

解决方案1:传递组件类型而非JSX元素

与其直接传递渲染好的JSX元素,不如把Icon组件本身作为props传递,然后在ToolbarButton内部渲染它。这样传递的是同一个组件引用,不会每次都创建新对象:

修改ToolbarComponent:

export const ToolbarComponent: React.FunctionComponent<ToolbarComponentProps> = (props) => {
  const { AIsTrue, BIsTrue, CIsTrue } = props;
  return (
    <Stack>
      <ToolbarButton text="FirstButton" icon={MyIcon} visible={AIsTrue || BIsTrue || CIsTrue } />
      <ToolbarButton text="SecondButton" icon={MyOtherIcon} visible={BIsTrue} />
    </Stack>
  );
};

修改ToolbarButton的props定义和渲染逻辑:

export interface IToolbarButtonProps {
  text?: string;
  icon: React.ElementType; // 改为组件类型
  visible?: boolean;
}

export const ToolbarButton: React.FunctionComponent<IToolbarButtonProps> = React.memo(
  (props) => {
    const { text, icon: Icon, visible } = props;
    const buttonClass = visible ? 'blah' : '';
    console.log('I rendered - ' + text);
    return (
      <Button className={buttonClass}>
        <Stack horizontal>
          <Icon /> {/* 在这里渲染组件 */}
          <Text>{text}</Text>
        </Stack>
      </Button>
    );
  },
  (prevProps, nextProps) => {
    // 现在icon是组件类型,引用不会变,加上其他props的检查
    return prevProps.text === nextProps.text &&
           prevProps.visible === nextProps.visible &&
           prevProps.icon === nextProps.icon;
  },
);

解决方案2:用useMemo缓存JSX元素

如果你更倾向于保持当前传递JSX元素的方式,可以在ToolbarComponent里用useMemo把Icon元素缓存起来,确保每次渲染时引用不变:

export const ToolbarComponent: React.FunctionComponent<ToolbarComponentProps> = (props) => {
  const { AIsTrue, BIsTrue, CIsTrue } = props;
  
  // 缓存Icon元素,只有当依赖变化时才重新创建
  const firstIcon = useMemo(() => <MyIcon />, []);
  const secondIcon = useMemo(() => <MyOtherIcon />, []);

  return (
    <Stack>
      <ToolbarButton text="FirstButton" icon={firstIcon} visible={AIsTrue || BIsTrue || CIsTrue } />
      <ToolbarButton text="SecondButton" icon={secondIcon} visible={BIsTrue} />
    </Stack>
  );
};

这样即使ToolbarComponent重新渲染,secondIcon的引用也不会变,你的React.memo比较函数就能正确识别props未变化,避免不必要的重渲染。

额外提示

你的React.memo比较函数目前只检查了icon,建议也加上text和visible的检查,确保所有相关props都被正确比较,避免其他不必要的重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 05:39:10