组件基础 #
一、组件概述 #
组件是 React 的核心概念,将 UI 拆分为独立、可复用的部分,每个组件管理自己的状态和逻辑。
1.1 组件定义 #
javascript
// 组件是返回JSX的函数
function Welcome() {
return <h1>Hello, React!</h1>;
}
1.2 组件特点 #
| 特点 | 说明 |
|---|---|
| 独立性 | 组件管理自己的状态和逻辑 |
| 可复用 | 组件可在不同地方重复使用 |
| 可组合 | 小组件组合成大组件 |
| 可测试 | 独立组件易于测试 |
二、函数组件 #
2.1 基本定义 #
javascript
// 函数声明
function Welcome() {
return <h1>Hello, React!</h1>;
}
// 函数表达式
const Welcome = function() {
return <h1>Hello, React!</h1>;
};
// 箭头函数
const Welcome = () => <h1>Hello, React!</h1>;
2.2 接收Props #
javascript
function Welcome({ name, age }) {
return (
<div>
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
</div>
);
}
// 使用
<Welcome name="Alice" age={25} />
2.3 带状态的函数组件 #
javascript
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
增加
</button>
</div>
);
}
三、类组件 #
3.1 基本定义 #
javascript
import { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, React!</h1>;
}
}
3.2 接收Props #
javascript
class Welcome extends Component {
render() {
const { name, age } = this.props;
return (
<div>
<h1>Hello, {name}!</h1>
<p>Age: {age}</p>
</div>
);
}
}
3.3 带状态的类组件 #
javascript
import { 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>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>增加</button>
</div>
);
}
}
3.4 类组件生命周期 #
javascript
import { Component } from 'react';
class LifecycleDemo extends Component {
constructor(props) {
super(props);
console.log('1. constructor');
this.state = { count: 0 };
}
static getDerivedStateFromProps(props, state) {
console.log('2. getDerivedStateFromProps');
return null;
}
componentDidMount() {
console.log('3. componentDidMount');
}
shouldComponentUpdate(nextProps, nextState) {
console.log('4. shouldComponentUpdate');
return true;
}
getSnapshotBeforeUpdate(prevProps, prevState) {
console.log('5. getSnapshotBeforeUpdate');
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
console.log('6. componentDidUpdate');
}
componentWillUnmount() {
console.log('7. componentWillUnmount');
}
render() {
console.log('render');
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
增加
</button>
</div>
);
}
}
四、函数组件 vs 类组件 #
4.1 对比表 #
| 特性 | 函数组件 | 类组件 |
|---|---|---|
| 语法 | 简洁 | 复杂 |
| 状态管理 | Hooks | this.state |
| 生命周期 | useEffect | 生命周期方法 |
| this | 无 | 需要绑定 |
| 性能 | 略优 | 略差 |
| 推荐程度 | 推荐 | 维护模式 |
4.2 代码对比 #
javascript
// 函数组件
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('组件挂载或更新');
return () => console.log('清理');
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
// 类组件
class Counter extends Component {
state = { count: 0 };
componentDidMount() {
console.log('组件挂载');
}
componentDidUpdate() {
console.log('组件更新');
}
componentWillUnmount() {
console.log('组件卸载');
}
render() {
return (
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
{this.state.count}
</button>
);
}
}
五、组件组合 #
5.1 组件嵌套 #
javascript
function Header() {
return <header>Header</header>;
}
function Main() {
return <main>Main Content</main>;
}
function Footer() {
return <footer>Footer</footer>;
}
function App() {
return (
<div>
<Header />
<Main />
<Footer />
</div>
);
}
5.2 children属性 #
javascript
function Card({ title, children }) {
return (
<div className="card">
<div className="card-header">
<h2>{title}</h2>
</div>
<div className="card-body">
{children}
</div>
</div>
);
}
function App() {
return (
<Card title="用户信息">
<p>Name: Alice</p>
<p>Age: 25</p>
</Card>
);
}
5.3 组件作为属性 #
javascript
function Layout({ header, sidebar, content, footer }) {
return (
<div className="layout">
<header>{header}</header>
<div className="main">
<aside>{sidebar}</aside>
<main>{content}</main>
</div>
<footer>{footer}</footer>
</div>
);
}
function App() {
return (
<Layout
header={<h1>My App</h1>}
sidebar={<nav>Navigation</nav>}
content={<article>Content</article>}
footer={<p>© 2024</p>}
/>
);
}
六、组件拆分原则 #
6.1 单一职责原则 #
每个组件只做一件事:
javascript
// ❌ 违反单一职责
function UserCard({ user }) {
return (
<div>
<img src={user.avatar} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<UserStats stats={user.stats} />
<UserPosts posts={user.posts} />
</div>
);
}
// ✅ 遵循单一职责
function UserCard({ user }) {
return (
<div>
<UserAvatar user={user} />
<UserInfo user={user} />
<UserStats stats={user.stats} />
<UserPosts posts={user.posts} />
</div>
);
}
6.2 组件粒度 #
text
组件层次
├── 页面组件(Page)
│ └── 整个页面
├── 布局组件(Layout)
│ └── 页面结构
├── 业务组件(Business)
│ └── 业务功能模块
└── 基础组件(UI)
└── 可复用UI组件
6.3 拆分时机 #
应该拆分的情况:
- 组件代码超过 200 行
- 组件有多个职责
- 部分逻辑可复用
- 组件状态过于复杂
不应该拆分的情况:
- 组件逻辑简单
- 拆分后增加复杂度
- 没有复用需求
七、组件命名规范 #
7.1 命名规则 #
javascript
// ✅ 好的命名:PascalCase
function UserProfile() {}
function ShoppingCart() {}
function NavigationBar() {}
// ❌ 不好的命名
function userProfile() {}
function shopping_cart() {}
7.2 文件命名 #
text
components/
├── UserProfile/
│ ├── index.jsx
│ ├── UserProfile.jsx
│ └── UserProfile.css
├── ShoppingCart/
│ └── index.jsx
└── NavBar/
└── index.jsx
7.3 组件名称要有意义 #
javascript
// ❌ 不好的命名
function Component1() {}
function Wrapper() {}
function Container() {}
// ✅ 好的命名
function UserAvatar() {}
function ModalDialog() {}
function FormContainer() {}
八、组件最佳实践 #
8.1 保持组件纯净 #
javascript
// ❌ 副作用
let count = 0;
function Counter() {
count++;
return <div>{count}</div>;
}
// ✅ 纯函数
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
{count}
<button onClick={() => setCount(c => c + 1)}>+</button>
</div>
);
}
8.2 Props验证 #
javascript
// 使用PropTypes(开发模式)
import PropTypes from 'prop-types';
function UserCard({ name, age, email }) {
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
<p>Email: {email}</p>
</div>
);
}
UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
email: PropTypes.string
};
UserCard.defaultProps = {
age: 0,
email: ''
};
8.3 避免prop drilling #
javascript
// ❌ prop drilling
function App() {
const user = { name: 'Alice' };
return <Layout user={user} />;
}
function Layout({ user }) {
return <Sidebar user={user} />;
}
function Sidebar({ user }) {
return <UserCard user={user} />;
}
// ✅ 使用Context或组合
function App() {
const user = { name: 'Alice' };
return (
<Layout>
<Sidebar>
<UserCard user={user} />
</Sidebar>
</Layout>
);
}
8.4 组件文档化 #
javascript
/**
* UserCard 组件 - 显示用户信息卡片
*
* @param {Object} props
* @param {string} props.name - 用户名
* @param {number} props.age - 年龄
* @param {string} props.email - 邮箱地址
*
* @example
* <UserCard name="Alice" age={25} email="alice@example.com" />
*/
function UserCard({ name, age, email }) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>Age: {age}</p>
<p>Email: {email}</p>
</div>
);
}
九、总结 #
| 要点 | 说明 |
|---|---|
| 优先函数组件 | 函数组件更简洁,推荐使用 |
| 单一职责 | 每个组件只做一件事 |
| 合理拆分 | 根据职责和复用需求拆分 |
| 规范命名 | 使用 PascalCase 命名 |
| 保持纯净 | 避免副作用 |
组件化开发核心:
- 组件是 React 应用的构建块
- 函数组件是现代 React 的首选
- 组件组合优于继承
- 保持组件简单、专注、可复用
最后更新:2026-03-26