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
相关产品推荐
相关产品推荐

