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

React中Counter组件状态为何重置?JSX大括号影响渲染位置吗?

为什么Counter组件状态会被重置?

首先得明确React保留组件状态的核心逻辑:React是根据组件在虚拟DOM树里的位置来匹配前后两次渲染的组件实例,从而决定是否保留状态,而非单纯看组件类型是否一致。

看你这段代码的执行逻辑:

  • 当isPlayerA为true时,第一个{}代码块渲染<Counter person="Taylor"/>,第二个{}代码块无输出;
  • 当isPlayerA切换为false时,第一个{}代码块为空,第二个{}代码块渲染<Counter person="Sarah"/>。

这意味着两个Counter在React的虚拟DOM结构中属于完全不同的位置节点:第一个条件分支里的Counter会在状态切换时被直接卸载,第二个分支里的是全新挂载的组件实例。新实例会重新执行useState初始化逻辑,之前的分数、hover状态自然就被重置了。

关于JSX大括号的疑问

{}只是JSX中嵌入JavaScript表达式的语法,本身不会直接导致组件位置变化。但你用了两个独立的条件表达式(两个{})分别渲染不同的Counter,相当于把两个Counter放在了虚拟DOM树的两个不同节点位置上。React会将它们判定为两个无关的组件,切换时销毁旧实例、创建新实例,状态也就随之重置。

如果想保留状态,只需让Counter始终在同一个位置渲染,仅修改person属性即可,示例代码如下:

import { useState } from 'react';

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组件代码不变
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始终处于虚拟DOM树的同一位置,React会识别为同一个组件实例,仅更新person属性,状态就能被保留。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 15:25:16