Appearance
React 组件基础
组件是 React 的核心概念之一,它允许我们将 UI 拆分为独立、可复用的部分。本章节将介绍 React 组件的基本概念和使用方法。
6.1 什么是组件?
组件的定义
组件是 React 应用的基本构建块,它是一个可以接收输入(props)并返回 React 元素的函数或类。
组件的作用
- 代码复用:可以在多个地方使用同一个组件
- 逻辑封装:将相关的 UI 和逻辑封装在一起
- 可维护性:使代码结构更清晰,易于维护
- 可测试性:便于单元测试
组件的优势
- 模块化:每个组件都有明确的职责
- 可组合性:组件可以嵌套和组合
- 可重用性:可以在不同的项目中使用
6.2 组件的两种类型
函数组件(推荐)
函数组件是 React 16.8+ 推荐的组件类型,它是一个简单的 JavaScript 函数,接收 props 作为参数并返回 React 元素。
jsx
// 函数组件
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}类组件
类组件是传统的组件类型,它是一个继承自 React.Component 的 JavaScript 类。
jsx
// 类组件
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}新手建议
- 优先使用函数组件:函数组件更简洁,易于理解和测试
- 了解类组件:在维护旧项目时可能会遇到类组件
6.3 组件的定义、导入与使用
定义组件
jsx
// src/components/Greeting.jsx
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
export default Greeting;导入组件
jsx
// src/App.jsx
import Greeting from './components/Greeting';
function App() {
return (
<div>
<Greeting name="React" />
</div>
);
}
export default App;使用组件
jsx
// 基本使用
<Greeting name="React" />
// 嵌套使用
function App() {
return (
<div>
<Header>
<Greeting name="React" />
</Header>
</div>
);
}6.4 组件 props
props 的传递与接收
传递 props:
jsx
<Greeting name="React" age={10} isActive={true} />接收 props:
jsx
// 解构赋值
function Greeting({ name, age, isActive }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>年龄:{age}</p>
<p>状态:{isActive ? '活跃' : '非活跃'}</p>
</div>
);
}
// 传统方式
function Greeting(props) {
return (
<div>
<h1>Hello, {props.name}!</h1>
<p>年龄:{props.age}</p>
<p>状态:{props.isActive ? '活跃' : '非活跃'}</p>
</div>
);
}props 类型限制
使用 PropTypes 来限制 props 的类型:
jsx
import PropTypes from 'prop-types';
function Greeting({ name, age, isActive }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>年龄:{age}</p>
<p>状态:{isActive ? '活跃' : '非活跃'}</p>
</div>
);
}
Greeting.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
isActive: PropTypes.bool
};
export default Greeting;props 默认值设置
jsx
function Greeting({ name, age = 10, isActive = true }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>年龄:{age}</p>
<p>状态:{isActive ? '活跃' : '非活跃'}</p>
</div>
);
}
// 或使用 defaultProps
Greeting.defaultProps = {
age: 10,
isActive: true
};props 不可修改原则
重要原则:props 是只读的,不能在组件内部修改 props。
jsx
// 错误
function Greeting({ name }) {
name = 'Modified'; // 不能修改 props
return <h1>Hello, {name}!</h1>;
}
// 正确
function Greeting({ name }) {
const modifiedName = `Hello, ${name}!`;
return <h1>{modifiedName}</h1>;
}6.5 组件状态
useState Hook
useState 是 React 提供的一个 Hook,用于在函数组件中管理状态。
基本使用:
jsx
import { useState } from 'react';
function Counter() {
// 声明一个名为 count 的状态变量,初始值为 0
// setCount 是更新 count 的函数
const [count, setCount] = useState(0);
return (
<div>
<p>计数:{count}</p>
<button onClick={() => setCount(count + 1)}>增加</button>
<button onClick={() => setCount(count - 1)}>减少</button>
<button onClick={() => setCount(0)}>重置</button>
</div>
);
}状态修改的注意事项
- 不能直接修改状态:必须使用 setter 函数
- 状态更新是异步的:React 可能会批量更新状态
- 状态更新会触发组件重新渲染
jsx
// 错误
function Counter() {
const [count, setCount] = useState(0);
function increment() {
count++; // 直接修改状态,不会触发重新渲染
}
return (
<div>
<p>计数:{count}</p>
<button onClick={increment}>增加</button>
</div>
);
}
// 正确
function Counter() {
const [count, setCount] = useState(0);
function increment() {
setCount(count + 1); // 使用 setter 函数
}
return (
<div>
<p>计数:{count}</p>
<button onClick={increment}>增加</button>
</div>
);
}复杂状态管理
对象类型状态
jsx
import { useState } from 'react';
function UserProfile() {
const [user, setUser] = useState({
name: '张三',
age: 20,
email: 'zhangsan@example.com'
});
function updateName(name) {
setUser(prevUser => ({
...prevUser,
name
}));
}
return (
<div>
<h1>{user.name}</h1>
<p>年龄:{user.age}</p>
<p>邮箱:{user.email}</p>
<input
type="text"
value={user.name}
onChange={e => updateName(e.target.value)}
/>
</div>
);
}数组类型状态
jsx
import { useState } from 'react';
function TodoList() {
const [todos, setTodos] = useState(['学习 React', '练习编程', '阅读文档']);
const [inputValue, setInputValue] = useState('');
function addTodo() {
if (inputValue) {
setTodos(prevTodos => [...prevTodos, inputValue]);
setInputValue('');
}
}
function removeTodo(index) {
setTodos(prevTodos => prevTodos.filter((_, i) => i !== index));
}
return (
<div>
<input
type="text"
value={inputValue}
onChange={e => setInputValue(e.target.value)}
/>
<button onClick={addTodo}>添加</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>
{todo}
<button onClick={() => removeTodo(index)}>删除</button>
</li>
))}
</ul>
</div>
);
}实战练习
练习1:基本组件
jsx
// src/components/Button.jsx
function Button({ text, onClick, className }) {
return (
<button className={className} onClick={onClick}>
{text}
</button>
);
}
Button.propTypes = {
text: PropTypes.string.isRequired,
onClick: PropTypes.func,
className: PropTypes.string
};
export default Button;
// 使用
import Button from './components/Button';
function App() {
function handleClick() {
console.log('Button clicked!');
}
return (
<div>
<Button text="点击我" onClick={handleClick} className="primary" />
</div>
);
}练习2:状态管理
jsx
import { useState } from 'react';
function Toggle() {
const [isOn, setIsOn] = useState(false);
return (
<div>
<p>状态:{isOn ? '开' : '关'}</p>
<button onClick={() => setIsOn(!isOn)}>
{isOn ? '关闭' : '打开'}
</button>
</div>
);
}练习3:复杂状态
jsx
import { useState } from 'react';
function Form() {
const [formData, setFormData] = useState({
name: '',
email: '',
password: ''
});
function handleChange(e) {
const { name, value } = e.target;
setFormData(prevData => ({
...prevData,
[name]: value
}));
}
function handleSubmit(e) {
e.preventDefault();
console.log('表单数据:', formData);
}
return (
<form onSubmit={handleSubmit}>
<div>
<label>姓名:</label>
<input
type="text"
name="name"
value={formData.name}
onChange={handleChange}
/>
</div>
<div>
<label>邮箱:</label>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
</div>
<div>
<label>密码:</label>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
</div>
<button type="submit">提交</button>
</form>
);
}通过本章节的学习,你已经掌握了 React 组件的基本概念和使用方法。组件是 React 开发的核心,掌握好组件的使用对于学习 React 至关重要。
