React 组件基础
概述
组件是 React 应用的基本构建块。每个 React 应用都是由组件组成的组件树。本章将学习如何创建和使用 React 组件,包括函数组件、类组件以及组件的组合。
🧩 什么是组件
组件的基本概念
jsx
// 最简单的函数组件
function Welcome() {
return <h1>Hello, World!</h1>;
}
// 使用组件
function App() {
return (
<div>
<Welcome />
<Welcome />
<Welcome />
</div>
);
}组件的特点
- 可复用:一次定义,多处使用
- 独立性:每个组件管理自己的状态
- 组合性:小组件组合成大组件
- 声明式:描述 UI 应该是什么样子
📝 函数组件
基础函数组件
jsx
// 无参数组件
function Header() {
return (
<header>
<h1>我的网站</h1>
<nav>
<a href="#home">首页</a>
<a href="#about">关于</a>
<a href="#contact">联系</a>
</nav>
</header>
);
}
// 带参数的组件
function Greeting({ name, time = "上午" }) {
return (
<div>
<h2>{time}好,{name}!</h2>
<p>欢迎来到我们的网站</p>
</div>
);
}
// 使用组件
function App() {
return (
<div>
<Header />
<Greeting name="张三" time="下午" />
<Greeting name="李四" />
</div>
);
}箭头函数组件
jsx
// 箭头函数写法
const Button = ({ children, onClick, type = "button" }) => {
return (
<button type={type} onClick={onClick}>
{children}
</button>
);
};
const Card = ({ title, content, imageUrl }) => (
<div className="card">
{imageUrl && <img src={imageUrl} alt={title} />}
<h3>{title}</h3>
<p>{content}</p>
</div>
);
// 组件组合
const ProductCard = ({ product }) => (
<Card
title={product.name}
content={product.description}
imageUrl={product.image}
/>
);🏗️ 类组件
基础类组件
jsx
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h2>计数器: {this.state.count}</h2>
<button onClick={this.increment}>
增加
</button>
</div>
);
}
}
// 带生命周期的类组件
class Timer extends Component {
constructor(props) {
super(props);
this.state = {
seconds: 0
};
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ seconds: this.state.seconds + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div>
<h3>已运行: {this.state.seconds} 秒</h3>
</div>
);
}
}🔧 Props 和 Children
Props 传递
jsx
function UserProfile({ user, showEmail = false, onEdit }) {
return (
<div className="user-profile">
<h2>{user.name}</h2>
<p>年龄: {user.age}</p>
{showEmail && <p>邮箱: {user.email}</p>}
<button onClick={() => onEdit(user.id)}>
编辑
</button>
</div>
);
}
// 使用 Props
function App() {
const user = {
id: 1,
name: "张三",
age: 25,
email: "zhangsan@example.com"
};
const handleEdit = (userId) => {
console.log(`编辑用户: ${userId}`);
};
return (
<UserProfile
user={user}
showEmail={true}
onEdit={handleEdit}
/>
);
}Children 属性
jsx
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay">
<div className="modal">
<button className="modal-close" onClick={onClose}>
×
</button>
{children}
</div>
</div>
);
}
function ConfirmDialog({ isOpen, onClose, onConfirm }) {
return (
<Modal isOpen={isOpen} onClose={onClose}>
<h3>确认操作</h3>
<p>您确定要执行此操作吗?</p>
<div className="modal-actions">
<button onClick={onConfirm}>确认</button>
<button onClick={onClose}>取消</button>
</div>
</Modal>
);
}🎯 组件组合模式
容器组件和展示组件
jsx
// 展示组件(只负责 UI)
function TodoItem({ todo, onToggle, onDelete }) {
return (
<div className={`todo-item ${todo.completed ? 'completed' : ''}`}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => onDelete(todo.id)}>删除</button>
</div>
);
}
// 容器组件(管理状态和逻辑)
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: '学习 React', completed: false },
{ id: 2, text: '写项目文档', completed: true }
]);
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div className="todo-list">
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
onDelete={deleteTodo}
/>
))}
</div>
);
}高阶组件模式
jsx
// 加载状态高阶组件
function withLoading(WrappedComponent) {
return function WithLoadingComponent({ isLoading, ...props }) {
if (isLoading) {
return <div className="loading">加载中...</div>;
}
return <WrappedComponent {...props} />;
};
}
// 使用高阶组件
const UserListWithLoading = withLoading(function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
});
function App() {
const [users, setUsers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setUsers([
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
]);
setIsLoading(false);
}, 2000);
}, []);
return (
<UserListWithLoading
users={users}
isLoading={isLoading}
/>
);
}🎨 组件样式
CSS 模块化
jsx
// Button.module.css
/*
.button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.primary {
background-color: #007bff;
color: white;
}
.secondary {
background-color: #6c757d;
color: white;
}
*/
import styles from './Button.module.css';
function Button({ variant = 'primary', children, ...props }) {
const buttonClass = `${styles.button} ${styles[variant]}`;
return (
<button className={buttonClass} {...props}>
{children}
</button>
);
}Styled Components
jsx
import styled from 'styled-components';
const StyledButton = styled.button`
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
background-color: ${props =>
props.variant === 'primary' ? '#007bff' : '#6c757d'
};
color: white;
&:hover {
opacity: 0.8;
}
`;
function Button({ variant, children, ...props }) {
return (
<StyledButton variant={variant} {...props}>
{children}
</StyledButton>
);
}📊 组件性能优化
React.memo
jsx
import { memo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, filter }) {
console.log('ExpensiveComponent 渲染');
const filteredData = data.filter(item =>
item.name.toLowerCase().includes(filter.toLowerCase())
);
return (
<ul>
{filteredData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
});
// 自定义比较函数
const CustomMemoComponent = memo(function Component({ user, settings }) {
return (
<div>
<h2>{user.name}</h2>
<p>主题: {settings.theme}</p>
</div>
);
}, (prevProps, nextProps) => {
return prevProps.user.id === nextProps.user.id &&
prevProps.settings.theme === nextProps.settings.theme;
});📝 本章小结
组件是 React 的核心概念,通过本章学习,你应该掌握了:
关键要点
- ✅ 函数组件和类组件的创建方式
- ✅ Props 的传递和使用
- ✅ Children 属性的应用
- ✅ 组件组合和复用模式
- ✅ 组件样式管理
- ✅ 基础性能优化技巧
最佳实践
- 优先使用函数组件:更简洁,性能更好
- 保持组件单一职责:每个组件只做一件事
- 合理使用 Props:保持接口简洁明了
- 组件命名要清晰:使用 PascalCase 命名
- 适当使用 memo:避免不必要的重新渲染
继续学习:下一章 - React 属性 Props