保留和重置状态
状态在组件之间是隔离的。React 根据它们在 UI 树中的位置来跟踪哪个状态属于哪个组件。您可以控制何时保留状态以及何时在重新渲染之间重置状态。
状态绑定到渲染树中的位置
React 为 UI 中的组件结构构建渲染树。
当您给出组件状态时,您可能会认为该状态“存在于”组件内部。但状态实际上是在 React 内部保存的。React 通过该组件在渲染树中的位置将它所持有的每个状态片段与正确的组件相关联。
在这里,只有一个 JSX 标签,但它呈现在两个不同的位置:<Counter />
import { useState } from 'react';
export default function App() {
const counter = <Counter />;
return (
<div>
{counter}
{counter}
</div>
);
}
function Counter() {
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>{score}</h1>
<button onClick={() => setScore(score + 1)}>
Add one
</button>
</div>
);
}
这是两个独立的计数器,因为每个计数器都呈现在树中自己的位置。使用 React 通常不需要考虑这些位置,但了解它的工作原理会很有用。
在 React 中,屏幕上的每个组件都具有完全隔离的状态。例如,如果并排渲染两个组件,则每个组件都将获得自己的独立和状态。Counter
score
hover
尝试单击两个计数器,并注意它们不会相互影响:
import { useState } from 'react';
export default function App() {
return (
<div>
<Counter />
<Counter />
</div>
);
}
function Counter() {
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>{score}</h1>
<button onClick={() => setScore(score + 1)}>
Add one
</button>
</div>
);
}
只要你在树中的同一位置渲染相同的组件,React 就会保持状态。要查看这一点,请递增两个计数器,然后通过取消选中“渲染第二个计数器”复选框来删除第二个组件,然后再次勾选它来重新添加它:
import { useState } from 'react';
export default function App() {
const [showB, setShowB] = useState(true);
return (
<div>
<Counter />
{showB && <Counter />}
<label>
<input
type="checkbox"
checked={showB}
onChange={e => {
setShowB(e.target.checked)
}}
/>
Render the second counter
</label>
</div>
);
}
function Counter() {
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>{score}</h1>
<button onClick={() => setScore(score + 1)}>
Add one
</button>
</div>
);
}