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

React组件在父组件中的position计算规则及示例疑问解答

React组件位置与State重置的疑问解析

问题背景

在React的一个示例中,切换isPlayerA状态时,两个Counter组件的State会被重置。示例代码如下:

import { useState } from 'react';

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      {isPlayerA &&
        <Counter person="Taylor" />
      }
      {!isPlayerA &&
        <Counter person="Sarah" />
      }
      <button onClick={() => {
        setIsPlayerA(!isPlayerA);
      }}>
        Next player!
      </button>
    </div>
  );
}

function Counter({ person }) {
  const [score, setScore] = useState(0);
  const [hover, setHover] = useState(false);

  let className = 'counter';
  if (hover) {
    className += ' hover';
  }

  return (
    <div
      className={className}
      onPointerEnter={() => setHover(true)}
      onPointerLeave={() => setHover(false)}
    >
      <h1>{person}'s score: {score}</h1>
      <button onClick={() => setScore(score + 1)}>
        Add one
      </button>
    </div>
  );
}

存在两个疑问:

  • 两个Counter最终渲染后都是父div的第一个子元素,为何文档称它们处于不同位置?
  • React中组件在父组件内的位置是如何计算的?

核心解析

1. 组件位置的判定逻辑

React判断组件是否为同一实例,依据的是JSX结构中的“逻辑位置”,而非最终渲染后的DOM位置。

在示例的JSX结构里,父div下包含三个逻辑节点:

  • 第一个逻辑节点:{isPlayerA && <Counter person="Taylor" />}(条件渲染表达式)
  • 第二个逻辑节点:{!isPlayerA && <Counter person="Sarah" />}(另一条件渲染表达式)
  • 第三个逻辑节点:<button>Next player!</button>

当isPlayerA为true时,第一个逻辑节点渲染出Counter,第二个节点返回null;切换为false后,第一个节点返回null,第二个节点渲染出Counter。对React而言,这两个Counter属于不同的逻辑位置节点,因此会被视为完全独立的组件实例,State自然会被重置。

2. DOM位置与逻辑位置的差异

虽然最终DOM中两个Counter都是父div的第一个子元素,但React的组件实例跟踪基于静态JSX结构的节点顺序,而非动态渲染后的DOM结构。React在更新比对时,会按JSX中节点的顺序(逻辑位置)匹配新旧组件。

3. 保留State的修改方案

若想让两个角色共享Counter的State,只需将Counter放在同一个逻辑位置,通过条件切换person属性即可:

export default function Scoreboard() {
  const [isPlayerA, setIsPlayerA] = useState(true);
  return (
    <div>
      <Counter person={isPlayerA ? "Taylor" : "Sarah"} />
      <button onClick={() => setIsPlayerA(!isPlayerA)}>
        Next player!
      </button>
    </div>
  );
}

此时Counter始终处于父div的第一个逻辑位置,React会判定为同一组件实例,State将被保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:45:07