React 19 入门教程
状态提升
本教程共 50 篇 · 第 17 篇 · 更新于 2026-07-29 · 约 7 分钟阅读
React状态提升props组件通信兄弟组件
17. 状态提升
本节目标:掌握”状态提升”模式,让多个组件共享同一份数据,实现兄弟组件之间的通信。
什么时候需要状态提升
两个兄弟组件需要同步数据时,把状态提到它们最近的公共父组件:
App(状态在这里)
/ \
Panel1 Panel2(都读到同一份状态)
一个温度转换的例子
摄氏度和华氏度输入框,需要实时同步:
function TemperatureConverter() {
const [celsius, setCelsius] = useState('');
const [fahrenheit, setFahrenheit] = useState('');
return (
<>
<CelsiusInput value={celsius} onChange={setCelsius} />
<FahrenheitInput value={fahrenheit} onChange={setFahrenheit} />
</>
);
}
但这样两个状态是独立的,改了摄氏度,华氏度不会跟着变。
提升状态到公共祖先
把温度值统一用摄氏度表示,提到父组件:
function TemperatureConverter() {
const [temperature, setTemperature] = useState('');
const [scale, setScale] = useState('c');
const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
function handleCelsiusChange(value) {
setTemperature(value);
setScale('c');
}
function handleFahrenheitChange(value) {
setTemperature(value);
setScale('f');
}
return (
<>
<CelsiusInput value={celsius} onChange={handleCelsiusChange} />
<FahrenheitInput value={fahrenheit} onChange={handleFahrenheitChange} />
</>
);
}
现在两个输入框共享同一份状态,改了任意一个,另一个自动更新。
子组件只负责展示和通知
子组件不持有状态,只通过 props 接收值和回调:
function CelsiusInput({ value, onChange }) {
return (
<fieldset>
<legend>摄氏度:</legend>
<input
value={value}
onChange={e => onChange(e.target.value)}
/>
</fieldset>
);
}
受控组件模式
子组件的值完全由父组件控制,这就是”受控组件”。下一章会详细讲。
数据流是单向的
父组件状态
↓ props(数据向下)
子组件渲染
↓ 用户输入
子组件调用回调
↑ 事件向上
父组件更新状态
↓
重新渲染,新数据再次向下流
这就是 React 的单向数据流。数据只能从父到子,事件只能从子到父。
单向数据流的好处
数据流向清晰,出了问题好排查。你知道数据一定来自父组件,不会从某个角落冒出来。
一个更实际的例子:搜索筛选
function ProductList({ products }) {
const [query, setQuery] = useState('');
const filtered = products.filter(p =>
p.name.toLowerCase().includes(query.toLowerCase())
);
return (
<>
<SearchBar value={query} onChange={setQuery} />
<ProductTable products={filtered} />
</>
);
}
function SearchBar({ value, onChange }) {
return (
<input
placeholder="搜索商品..."
value={value}
onChange={e => onChange(e.target.value)}
/>
);
}
function ProductTable({ products }) {
return (
<ul>
{products.map(p => <li key={p.id}>{p.name}</li>)}
</ul>
);
}
搜索框和商品列表共享 query 状态,但状态只存在于父组件。
什么时候不该提升
不是所有状态都需要提升。如果一个状态只在一个组件内部用,就留在那里:
- 表单输入的临时值 → 留在表单组件
- 弹窗的开关 → 留在弹窗组件
- 多个组件都要读的数据 → 提升到公共祖先
不要过度提升
状态提得太高,props 链会很长。中间组件被迫传递它不关心的 props。后面会讲 Context 解决这个问题。
本节要点
- 兄弟组件共享状态 → 提升到公共父组件
- 数据通过 props 向下传,事件通过回调向上传
- 子组件可以是纯受控的,不持有状态
- 单向数据流让状态变化可预测