Props 和 State 概述
React 组件通过 props(属性)和 state(状态)来管理和传递数据。理解它们的区别是掌握 React 的关键。
Props(属性)
Props 是什么
Props 是从父组件传递给子组件的数据。Props 是只读的,子组件不能修改接收到的 props。
传递 Props
// 父组件
function App() {
const userData = {
name: '张三',
age: 25,
city: '北京'
};
return (
<UserProfile
name={userData.name}
age={userData.age}
city={userData.city}
/>
);
}
// 子组件
function UserProfile({ name, age, city }) {
return (
<div>
<h2>用户信息</h2>
<p>姓名:{name}</p>
<p>年龄:{age}</p>
<p>城市:{city}</p>
</div>
);
}
Props 的默认值
function Button({ label, type = 'button', disabled = false }) {
return (
<button type={type} disabled={disabled}>
{label}
</button>
);
}
// 使用
<Button label="提交" />
<Button label="禁用按钮" disabled={true} />
Props 验证(PropTypes)
import PropTypes from 'prop-types';
function UserProfile({ name, age, city }) {
return (
<div>
<h2>{name}</h2>
<p>{age}岁</p>
<p>来自{city}</p>
</div>
);
}
UserProfile.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
city: PropTypes.string
};
UserProfile.defaultProps = {
age: 18,
city: '未知'
};
State(状态)
State 是什么
State 是组件内部管理的动态数据。当 state 改变时,组件会重新渲染。
使用 useState Hook
import { useState } from 'react';
function Counter() {
// 声明一个叫 count 的 state 变量,初始值为 0
const [count, setCount] = useState(0);
return (
<div>
<p>你点击了 {count} 次</p>
<button onClick={() => setCount(count + 1)}>
点击我
</button>
</div>
);
}
多个 State 变量
function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(18);
const handleSubmit = () => {
console.log({ name, email, age });
};
return (
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="姓名"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="邮箱"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(Number(e.target.value))}
/>
<button type="submit">提交</button>
</form>
);
}
Props vs State
| 特性 | Props | State |
|---|---|---|
| 来源 | 从父组件接收 | 组件内部管理 |
| 可变性 | 只读(不能修改) | 可变(可以修改) |
| 作用域 | 父组件控制 | 组件内部控制 |
| 用途 | 传递数据、回调 | 管理组件内部状态 |
数据流
单向数据流
React 遵循单向数据流原则:数据只能从父组件流向子组件。
// 父组件
function Parent() {
const [message, setMessage] = useState('Hello from Parent');
return (
<div>
<Child message={message} onUpdate={setMessage} />
</div>
);
}
// 子组件
function Child({ message, onUpdate }) {
return (
<div>
<p>{message}</p>
<button onClick={() => onUpdate('Updated from Child')}>
更新消息
</button>
</div>
);
}
状态提升
当多个组件需要共享状态时,将状态提升到它们最近的共同父组件。
// 状态提升前(不好)
function CelsiusInput({ value, onChange }) {
return (
<fieldset>
<legend>摄氏度</legend>
<input
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</fieldset>
);
}
function FahrenheitInput({ value, onChange }) {
return (
<fieldset>
<legend>华氏度</legend>
<input
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</fieldset>
);
}
// 状态提升后(好)
function TemperatureCalculator() {
const [temperature, setTemperature] = useState('');
const [scale, setScale] = useState('c');
const handleCelsiusChange = (value) => {
setTemperature(value);
setScale('c');
};
const handleFahrenheitChange = (value) => {
setTemperature(value);
setScale('f');
};
const celsius =
scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;
const fahrenheit =
scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;
return (
<div>
<CelsiusInput
value={celsius}
onChange={handleCelsiusChange}
/>
<FahrenheitInput
value={fahrenheit}
onChange={handleFahrenheitChange}
/>
</div>
);
}
💡 最佳实践
- Props 命名清晰:使用有意义的 prop 名称
- 避免过度提升状态:只在需要共享时才提升
- 保持 state 简单:避免冗余的 state
- 使用默认值:为可选 props 提供合理的默认值
🎯 练习
- 创建一个用户信息卡片组件,使用 props 传递数据
- 实现一个计数器组件,使用 state 管理计数
- 创建一个待办事项列表,练习状态提升
下一节我们将学习 组件生命周期和 useEffect Hook!