🚀 零基础全栈 React 入门(三):状态管理与事件处理
一、事件处理基础
1.1 React 事件绑定
React 事件采用驼峰命名法,事件处理函数作为属性传递。
function Button() {
const handleClick = () => {
console.log('按钮被点击了!');
};
return <button onClick={handleClick}>点击我</button>;
}
1.2 事件对象
function Button() {
const handleClick = (e) => {
e.preventDefault(); // 阻止默认行为
console.log('事件对象:', e);
};
return <button onClick={handleClick}>点击</button>;
}
1.3 向事件处理函数传递参数
方式一:使用箭头函数
function ListItem({ item }) {
const handleClick = () => {
console.log('点击了:', item.name);
};
return <li onClick={handleClick}>{item.name}</li>;
}
方式二:使用 bind
function ListItem({ item }) {
const handleClick = (item) => {
console.log('点击了:', item.name);
};
return <li onClick={handleClick.bind(this, item)}>{item.name}</li>;
}
二、状态管理进阶
2.1 复杂状态管理
import { useState } from 'react';
function UserProfile() {
const [user, setUser] = useState({
name: '小明',
age: 25,
isOnline: true
});
const toggleOnline = () => {
// 正确:使用展开运算符更新对象
setUser(prev => ({
...prev,
isOnline: !prev.isOnline
}));
};
return (
<div>
<h2>{user.name}</h2>
<p>年龄: {user.age}</p>
<p>状态: {user.isOnline ? '在线' : '离线'}</p>
<button onClick={toggleOnline}>切换状态</button>
</div>
);
}
2.2 数组状态管理
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习 React', completed: false },
{ id: 2, text: '完成作业', completed: true }
]);
// 添加待办事项
const addTodo = (text) => {
const newTodo = {
id: Date.now(),
text,
completed: false
};
setTodos(prev => [...prev, newTodo]);
};
// 切换完成状态
const toggleTodo = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
return (
<div>
<ul>
{todos.map(todo => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}
三、表单处理
3.1 受控组件
表单元素的值由 React 状态控制:
import { useState } from 'react';
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
console.log('用户名:', username);
console.log('密码:', password);
};
return (
<form onSubmit={handleSubmit}>
<div>
<label>用户名:</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</div>
<div>
<label>密码:</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
<button type="submit">登录</button>
</form>
);
}
3.2 多个表单字段优化
import { useState } from 'react';
function RegisterForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('表单数据:', formData);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
placeholder="用户名"
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
placeholder="邮箱"
/>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
placeholder="密码"
/>
<button type="submit">注册</button>
</form>
);
}
四、条件渲染进阶
4.1 元素变量
function Greeting({ isLoggedIn, user }) {
let greeting;
if (isLoggedIn) {
greeting = <h1>欢迎回来, {user.name}!</h1>;
} else {
greeting = <h1>请先登录</h1>;
}
return <div>{greeting}</div>;
}
4.2 组件级条件渲染
function LoginButton({ onLogin }) {
return <button onClick={onLogin}>登录</button>;
}
function LogoutButton({ onLogout }) {
return <button onClick={onLogout}>退出登录</button>;
}
function AuthButton({ isLoggedIn, onLogin, onLogout }) {
if (isLoggedIn) {
return <LogoutButton onLogout={onLogout} />;
}
return <LoginButton onLogin={onLogin} />;
}
五、列表渲染进阶
5.1 Key 的重要性
// ❌ 错误:使用 index 作为 key(不推荐)
const list = items.map((item, index) => (
<li key={index}>{item.name}</li>
));
// ✅ 正确:使用唯一 ID 作为 key
const list = items.map(item => (
<li key={item.id}>{item.name}</li>
));
5.2 列表操作示例
import { useState } from 'react';
function ShoppingList() {
const [items, setItems] = useState([
{ id: 1, name: '牛奶', quantity: 2 },
{ id: 2, name: '面包', quantity: 1 }
]);
// 删除项
const removeItem = (id) => {
setItems(prev => prev.filter(item => item.id !== id));
};
// 更新数量
const updateQuantity = (id, delta) => {
setItems(prev => prev.map(item =>
item.id === id
? { ...item, quantity: Math.max(0, item.quantity + delta) }
: item
));
};
return (
<ul>
{items.map(item => (
<li key={item.id}>
<span>{item.name}</span>
<button onClick={() => updateQuantity(item.id, -1)}>-</button>
<span>{item.quantity}</span>
<button onClick={() => updateQuantity(item.id, 1)}>+</button>
<button onClick={() => removeItem(item.id)}>删除</button>
</li>
))}
</ul>
);
}
六、状态提升
6.1 什么是状态提升
当多个组件需要共享状态时,将状态提升到它们的共同父组件中。
// 子组件:显示温度
function TemperatureDisplay({ temperature }) {
return <p>当前温度: {temperature}°C</p>;
}
// 子组件:温度控制
function TemperatureControl({ temperature, onTemperatureChange }) {
return (
<div>
<button onClick={() => onTemperatureChange(temperature - 1)}>-</button>
<span>{temperature}</span>
<button onClick={() => onTemperatureChange(temperature + 1)}>+</button>
</div>
);
}
// 父组件:管理状态
function Thermostat() {
const [temperature, setTemperature] = useState(20);
return (
<div>
<TemperatureDisplay temperature={temperature} />
<TemperatureControl
temperature={temperature}
onTemperatureChange={setTemperature}
/>
</div>
);
}
七、常见错误
7.1 直接修改状态
错误:
const [count, setCount] = useState(0);
// ❌ 直接修改状态
count = count + 1;
正确:
// ✅ 使用 setState
setCount(count + 1);
7..2 忘记阻止默认行为
错误:
function handleSubmit(e) {
// ❌ 表单会重新加载页面
console.log('提交');
}
正确:
function handleSubmit(e) {
e.preventDefault(); // ✅ 阻止默认行为
console.log('提交');
}
7.3 事件处理函数中的 this 问题
错误:
// ❌ 在类组件中,this 指向问题
<button onClick={this.handleClick}>点击</button>
正确:
// ✅ 使用箭头函数
<button onClick={() => this.handleClick()}>点击</button>
// ✅ 或者在 constructor 中绑定
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
八、总结与练习
8.1 本章要点
- ✅ React 事件使用驼峰命名
- ✅ 使用 useState 管理组件状态
- ✅ 状态更新必须使用 setState 函数
- ✅ 表单处理使用受控组件模式
- ✅ 列表渲染必须添加 key 属性
- ✅ 状态提升用于组件间共享状态
8.2 课后练习
- 创建一个待办事项应用(添加、删除、完成状态切换)
- 创建一个用户注册表单(包含用户名、邮箱、密码)
- 创建一个计数器组件,支持加减和重置功能
📌 系列文章导航:
- 第一篇:React 入门前置与环境搭建
- 第二篇:JSX 语法与组件基础
- 第三篇:状态管理与事件处理(当前)
- 第四篇:React Router 路由配置