组件化
React 的组件化是其核心设计思想之一,通过将 UI 拆分为独立、可复用的组件,开发者可以更高效地维护、扩展和协作开发。
一、组件的核心概念
组件(Component)是 React 应用的基本构成单元,本质是一个可复用的 UI 片段,封装了自身的结构(HTML)、样式(CSS)和逻辑(JavaScript)。通过组合多个组件,可以构建复杂的整个应用界面。
1. 优点
- 可复用性:一次编写,多处使用(如按钮、导航栏)
- 可维护性:修改单个组件不影响其他部分
- 可测试性:独立组件更容易编写单元测试
- 协作友好:团队可并行开发不同组件
- 逻辑清晰:组件化让代码结构更清晰,职责更分明,新人更容易理解项目结构
2. 设计原则
- 单一职责:每个组件只负责一个功能
- 高内聚,低耦合:组件内部的逻辑应当紧密相关(高内聚),而组件之间的依赖应该尽可能少(低耦合)
- 可复用性优先:设计组件时,考虑其通用性。尽量让组件不依赖特定的业务逻辑,通过
props来配置行为 - 命名清晰:组件名应当清晰的反映其功能
- 可组合性:通过组合小组件构成大组件,而非继承
- 避免过度嵌套:虽然可以组合,但过深的组件嵌套会使的代码难以理解和调试。适时的将复杂的逻辑提取到可独立的组件或 Hook 中
- Props 约束:明确 Props 的类型和默认值
- 状态最小化:仅将必要的状态保留在组件内部,避免冗余
- 性能意识:对高频更新的组件使用
React.memo、useMemo优化
二、组件的两种形式
React 支持两种形式的组件定义方式,目前 函数组件 + Hooks 是官方推荐的方案(React 16.8+)。
1.函数组件(Function Component)
用 JavaScript 函数定义,通过 return 返回 JSX(UI 结构)。
具有轻量、简洁的特定,依赖于 Hooks 管理状态和副作用。
// 使用函数式定义
function Title(props) {
return <h1>你好,{props.name}</h1>
}
// 使用箭头函数
const Title = (props) => <h1>你好,{props.name}</h1>
<Title name="Tom" /> // 渲染为 <h1>你好,Tom</h1>
2.类组件(Class Component)
用 ES6 类定义,需要继承 React.Component 或 React.PureComponent ,并通过 render() 方法返回 JSX。
是早期的主流方案,支持生命周期方法(如 componentDidMount),但代码量比较大。
class Title extends React.Component {
render() {
return <h1>你好,{this.props.name}</h1>;
}
}
3. 两种方式对比
- 函数式组件:
- 更符合现代前端趋势
- 配合 Hooks 可完全代替类组件的功能(状态、副作用、生命周期)
- 代码更简洁
- 性能通常更好
- 当前 React 开发的首选和推荐模式
- 没有
this上下文问题(函数作用域),无需处理this绑定(事件回调无需手动bind)
- 类组件:
- 需要注意
this指向。类方法默认不绑定this,若在事件回调中使用需要在构造函数手动绑定或使用箭头函数 - 有完整的生命周期
- 所有的状态集中在一个对象中,可能导致状态逻辑臃肿;复用逻辑需要通过高阶组件(HOC)或 Render Props ,增加了组件树的复杂度
- 需要注意
三、组件的核心属性:Props 和 State
组件的行为通过由 外部输入(Props) 和 内部状态(State) 共同驱动。
1. Props:父组件向子组件传递数据
Props 是组件的只读输入,用于接收父组件传递的数据(如配置、子节点等)。
- 不可变:子组件无法直接修改 Props (单向数据流)
- 类型检查:通过 prop-types 库或 TypeScript 约束类型
2. State(状态):组件内部管理的可变数据
State 是组件的私有属性,通过 setState (类组件)或 useState() (函数式组件)更新,会触发组件重新渲染。
- 可变但受控:需通过特定的方法更新,直接修改值不会出发渲染
- 异步更新:
setState和useState的更新是异步的(批量处理优化性能) - 合并更新:
setState会合并新旧状态对象
- 函数式组件
- 类式组件
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
// 或使用更新函数(避免闭包问题) setCount(prev => prev + 1)
};
return (
<div>
<p>点击次数:{count}</p>
<button onClick={handleClick}>+ 1</button>
</div>
);
}
class Counter extends React.Component {
state = {
count: 0,
};
constructor(props) {
super(props);
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
// 或使用更新函数 this.setState(prev => ({count : prev.count + 1}))
};
render() {
return (
<div>
<p>点击次数:{this.state.count}</p>
<button onClick={this.handleClick}>+1</button>
</div>
);
}
}
四、 组件的组合和嵌套
React 鼓励 组合(Composition) 而非继承(Inheritance)来复用组件逻辑。通过嵌套组件,可以构建复杂的 UI 结构。
1. Children 属性:传递子节点
通过 props.children 可以接收父组件包裹的内容,实现类似“插槽”功能
function Wrapper(props) {
return <div className="wrapper">{props.children}</div>;
}
<Wrapper>
<h1>你好,Tom</h1>
<p>你看见 Jerry 了没有</p>
</Wrapper>;
2. 自定义属性:传递任意子节点或配置
除了 children 外,可通过自定义属性传递更加复杂的结构(如数组、对象)。
function Layout({ header, content, footer }) {
return (
<div>
<header>{header}</header>
<main>{content}</main>
<footer>{footer}</footer>
</div>
);
}
<Layout
header={<h1>你好,Tom<h1/>}
content={<p>Jerry 丢了</p>}
footer={<p>2025 年 10 月 29 日</p>}
/>