Props 和 State
本章节将介绍 React 中两个核心概念:props 和 state。
props
props 是组件的输入参数,用于从父组件向子组件传递数据。
接收 props
function Welcome({ name, age }) {
return (
<div>
<h1>你好,{name}!</h1>
<p>你今年 {age} 岁了</p>
</div>
);
}
使用 props
function App() {
return (
<div>
<Welcome name="张三" age={20} />
<Welcome name="李四" age={25} />
</div>
);
}
props 的类型检查
安装 PropTypes:
npm install prop-types
使用 PropTypes:
import PropTypes from "prop-types";
function UserCard({ name, age, email }) {
return (
<div>
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
email: PropTypes.string
};
UserCard.defaultProps = {
age: 0,
email: ""
};
使用 TypeScript(可选)
interface UserProps {
name: string;
age?: number;
email?: string;
}
function UserCard({ name, age = 0, email = "" }: UserProps) {
return (
<div>
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}
state
state 是组件内部的状态数据,用于存储组件的动态数据。
useState Hook
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>计数: {count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
</div>
);
}
useState 返回一个数组:
- 第一个元素:当前状态值
- 第二个元素:更新状态的函数
多个 state
function UserForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [age, setAge] = useState(0);
return (
<form>
<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(parseInt(e.target.value))}
placeholder="年龄"
/>
</form>
);
}
复杂 state
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "学习 React", done: false },
{ id: 2, text: "做练习", done: true }
]);
const addTodo = (text) => {
setTodos([
...todos,
{ id: Date.now(), text, done: false }
]);
};
const toggleTodo = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
};
return (
<div>
<ul>
{todos.map((todo) => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
style={{
textDecoration: todo.done ? "line-through" : "none"
}}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
状态更新是异步的
React 可能会批量更新状态:
function Example() {
const [count, setCount] = useState(0);
// 错误:count 不会立即更新
const handleClick = () => {
setCount(count + 1);
console.log(count); // 可能是旧值
};
// 正确:使用函数形式
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
};
// 连续更新
const handleClick = () => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
// 结果是 +2
};
return <button onClick={handleClick}>{count}</button>;
}
useState 的初始值
// 简单值
const [count, setCount] = useState(0);
// 函数(只执行一次)
const [todos, setTodos] = useState(() => {
// 从 localStorage 读取
const saved = localStorage.getItem("todos");
return saved ? JSON.parse(saved) : [];
});
// 避免的问题
const [items, setItems] = useState(expensiveCompute()); // 每次渲染都执行
const [items, setItems] = useState(() => expensiveCompute()); // 只执行一次
props vs state
| 特性 | props | state |
|---|---|---|
| 来自父组件 | ✅ | ❌ |
| 组件内部管理 | ❌ | ✅ |
| 可修改 | ❌(只读) | ✅ |
| 引起组件重新渲染 | ✅ | ✅ |
实际示例:计数器
function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);
const increment = () => {
setCount(count + step);
};
const decrement = () => {
setCount(count - step);
};
const reset = () => {
setCount(0);
};
const changeStep = (newStep) => {
setStep(newStep);
};
return (
<div>
<h1>计数器</h1>
<p>当前值: {count}</p>
<p>步长: {step}</p>
<button onClick={increment}>+{step}</button>
<button onClick={decrement}>-{step}</button>
<button onClick={reset}>重置</button>
<div>
<button onClick={() => changeStep(1)}>步长 1</button>
<button onClick={() => changeStep(5)}>步长 5</button>
<button onClick={() => changeStep(10)}>步长 10</button>
</div>
</div>
);
}
小结
本章我们学习了:
- props 的概念和使用
- props 的类型检查
- state 的概念和使用
- useState Hook 的用法
- 多个 state 和复杂 state
- props 和 state 的区别
练习
- 创建一个显示当前时间的时钟组件
- 创建一个待办事项列表,支持添加、删除、标记完成
- 创建一个表单组件,包含姓名、邮箱、密码字段
- 创建一个评分组件,点击星标进行评分