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

React状态保留与重置:为何两个Counter渲染示例的位置判定结果不同?

默认情况下,当组件保持在同一位置时,React会保留该组件的状态。通常这正是你需要的效果,因此该默认行为是合理的。

示例取自新版React官方文档。

核心判定规则前置说明

React所说的「组件位置」,指的是虚拟DOM树中的节点层级、顺序索引,和浏览器渲染后的页面视觉位置无关,也和单次渲染是否仅出现一个同类型组件无关。判断组件是否复用实例的核心依据是:虚拟DOM位置 + 组件类型,两者完全一致才会复用原有实例、保留状态。


示例1 - 相同位置

核心渲染逻辑:

return (
  <div>
    {isPlayerA ? (
      <Counter person="Taylor" />
    ) : (
      <Counter person="Sarah" />
    )}
    <button onClick={() => {
      setIsPlayerA(!isPlayerA);
    }}>
      Next player!
    </button>
  </div>
); 

该写法中,两个Counter都在同一个三元表达式的返回结果里,对应div父节点下的第一个子节点槽位。isPlayerA切换时,只是这个槽位里的Counter的personprop发生了变化,React判定为同一位置的同一类型组件,会复用原有Counter实例,保留score等状态。


示例2 - 不同位置

核心渲染逻辑:

return (
  <div>
    {isPlayerA &&
      <Counter person="Taylor" />
    }
    {!isPlayerA &&
      <Counter person="Sarah" />
    }
    <button onClick={() => {
      setIsPlayerA(!isPlayerA);
    }}>
      Next player!
    </button>
  </div>
);

该写法中,两个Counter分别属于两个独立的条件渲染语句,对应div父节点下的两个不同顺序的子节点槽位:第一个槽位对应isPlayerA && ...的返回值,第二个槽位对应!isPlayerA && ...的返回值。
当isPlayerA切换为false时,第一个槽位的Counter会被销毁;第二个槽位原本是空值,现在会新建一个Counter实例。React判定两个Counter属于不同位置的组件,不会复用实例,原有状态会被重置。


你遗漏的核心规则要点

  • 虚拟DOM的子节点是按顺序逐个比对的,每个顺序位置对应独立的槽位,哪怕某个槽位渲染结果是空值,槽位本身也依然存在
  • 多个独立的条件渲染语句,会占据父组件下多个不同的顺序槽位,互相独立
  • 组件状态是绑定在「虚拟DOM槽位 + 组件类型」对应的实例上的,槽位变化就会触发实例销毁重建,状态自然不会保留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 19:45:03