组件是 React 的核心,掌握组件化思维是进阶 React 的关键
什么是组件?
组件是 React 应用的基本构建块。你可以把它想象成乐高积木——每个积木(组件)可以独立存在,通过组合形成复杂的结构(整个应用)。
┌─────────────────────────────────────┐
│ App 组件 │
│ ┌─────────┐ ┌─────────┐ │
│ │ Header │ │ Content │ │
│ └─────────┘ └─────────┘ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Sidebar │ │ Footer │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────┘
函数组件 vs 类组件
函数组件(推荐)
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// 使用
<Welcome name="Panbo" />
类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
推荐使用函数组件:现代 React 开发中,函数组件配合 Hooks 是主流写法。
组件的拆分原则
1. 单一职责
每个组件只负责一个功能:
// ❌ 职责过多
function UserProfile() {
return (
<div>
<h1>用户信息</h1>
<UserAvatar />
<UserBio />
<EditButton />
<FollowButton />
<UserPosts />
<UserStats />
</div>
);
}
// ✅ 单一职责拆分
function UserProfile() {
return (
<div>
<Header />
<UserInfo />
<Actions />
<UserContent />
</div>
);
}
2. 复用性
提取公共组件:
// ❌ 重复代码
function LoginForm() {
return (
<div>
<input type="text" placeholder="用户名" />
<input type="password" placeholder="密码" />
<button>登录</button>
</div>
);
}
function RegisterForm() {
return (
<div>
<input type="text" placeholder="用户名" />
<input type="password" placeholder="密码" />
<button>注册</button>
</div>
);
}
// ✅ 提取公共组件
function InputField({ placeholder, type = "text" }) {
return <input type={type} placeholder={placeholder} />;
}
function AuthForm({ buttonText }) {
return (
<div>
<InputField placeholder="用户名" />
<InputField placeholder="密码" type="password" />
<button>{buttonText}</button>
</div>
);
}
3. 层级清晰
├── App # 根组件
│ ├── Header # 页面头部
│ │ ├── Logo
│ │ ├── Nav
│ │ └── SearchBar
│ ├── MainContent # 主要内容
│ │ ├── PostList # 文章列表
│ │ │ └── PostCard # 单篇文章
│ │ └── Sidebar # 侧边栏
│ │ ├── Categories
│ │ └── Tags
│ └── Footer # 页脚
组件通信
1. Props 向下传递
// 父组件
function App() {
const message = 'Hello from Parent!';
return <ChildComponent message={message} />;
}
// 子组件
function ChildComponent({ message }) {
return <p>{message}</p>;
}
2. 回调函数向上传递
function Parent() {
const handleChildClick = (data) => {
console.log('收到子组件数据:', data);
};
return <Child onClick={handleChildClick} />;
}
function Child({ onClick }) {
return <button onClick={() => onClick('some data')}>点击</button>;
}
3. Context 跨层级传递
// 创建 Context
const ThemeContext = React.createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
// 不需要逐层传递
return <ThemeButton />;
}
function ThemeButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>主题按钮</button>;
}
组件的 props
Props 的只读性
Props 是只读的,组件不能修改自己的 props:
// ❌ 错误:props 是只读的
function Component(props) {
props.name = 'new name'; // 报错!
return <div>{props.name}</div>;
}
// ✅ 正确:props 是只读的,应该通过 state 来管理可变数据
默认 Props
function Button({ text = '点击', onClick }) {
return <button onClick={onClick}>{text}</button>;
}
// 使用
<Button /> // text 为 "点击"
<Button text="提交" /> // text 为 "提交"
Props 解构
function UserCard({ name, age, email, avatar }) {
return (
<div className="user-card">
<img src={avatar} alt={name} />
<h3>{name}</h3>
<p>{age} 岁</p>
<p>{email}</p>
</div>
);
}
// 使用
<UserCard
name="Panbo"
age={18}
email="panbo@example.com"
avatar="/avatar.png"
/>
组件设计最佳实践
- 保持简洁:一个组件应该可以在一屏内写完
- 命名清晰:使用有意义的名称,如
UserAvatar而非UA - 合理拆分:当一个组件职责过多时,考虑拆分
- 样式隔离:使用 CSS Modules 或 styled-components
- 错误边界:添加适当的错误处理
总结
本章我们学习了:
- 组件的概念和两种写法(函数组件 vs 类组件)
- 组件拆分的原则(单一职责、复用性、层级清晰)
- 组件之间的通信方式(Props、回调、Context)
- Props 的特性和最佳实践
下一章我们将深入学习 React 的核心概念——Props 与 State。