一、React组件概述
1.1 React组件的基本概念
React组件是构建用户界面的独立、可复用的代码单元。组件可以将复杂的UI拆分成多个独立、可维护的部分,每个组件负责渲染页面中的一部分内容。在React中,组件接收输入(props)并返回描述屏幕展示内容的React元素。
1.2 组件化开发的优势
组件化开发带来了诸多好处,包括代码复用性提升、维护成本降低、团队协作效率提高等。通过组件化,开发者可以像搭积木一样快速构建复杂的应用界面,同时每个组件都可以独立测试和开发。
1.3 React组件的两大分类
在React的发展历程中,主要存在两种组件形式:类组件和函数组件。类组件是React早期的主要编写方式,而函数组件随着Hooks的引入逐渐成为主流。下面通过流程图展示两者的关系与核心特征:
#publish-mermaid-1787762378893-0{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1787762378893-0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762378893-0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762378893-0 .error-icon{fill:#552222;}#publish-mermaid-1787762378893-0 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1787762378893-0 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1787762378893-0 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1787762378893-0 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1787762378893-0 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1787762378893-0 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1787762378893-0 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1787762378893-0 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1787762378893-0 .marker.cross{stroke:#333333;}#publish-mermaid-1787762378893-0 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1787762378893-0 p{margin:0;}#publish-mermaid-1787762378893-0 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1787762378893-0 .cluster-label text{fill:#333;}#publish-mermaid-1787762378893-0 .cluster-label span{color:#333;}#publish-mermaid-1787762378893-0 .cluster-label span p{background-color:transparent;}#publish-mermaid-1787762378893-0 .label text,#publish-mermaid-1787762378893-0 span{fill:#333;color:#333;}#publish-mermaid-1787762378893-0 .node rect,#publish-mermaid-1787762378893-0 .node circle,#publish-mermaid-1787762378893-0 .node ellipse,#publish-mermaid-1787762378893-0 .node polygon,#publish-mermaid-1787762378893-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762378893-0 .rough-node .label text,#publish-mermaid-1787762378893-0 .node .label text,#publish-mermaid-1787762378893-0 .image-shape .label,#publish-mermaid-1787762378893-0 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1787762378893-0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1787762378893-0 .rough-node .label,#publish-mermaid-1787762378893-0 .node .label,#publish-mermaid-1787762378893-0 .image-shape .label,#publish-mermaid-1787762378893-0 .icon-shape .label{text-align:center;}#publish-mermaid-1787762378893-0 .node.clickable{cursor:pointer;}#publish-mermaid-1787762378893-0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1787762378893-0 .arrowheadPath{fill:#333333;}#publish-mermaid-1787762378893-0 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1787762378893-0 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1787762378893-0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762378893-0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1787762378893-0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762378893-0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1787762378893-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1787762378893-0 .cluster text{fill:#333;}#publish-mermaid-1787762378893-0 .cluster span{color:#333;}#publish-mermaid-1787762378893-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1787762378893-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1787762378893-0 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1787762378893-0 .icon-shape,#publish-mermaid-1787762378893-0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762378893-0 .icon-shape p,#publish-mermaid-1787762378893-0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1787762378893-0 .icon-shape .label rect,#publish-mermaid-1787762378893-0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762378893-0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1787762378893-0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1787762378893-0 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node rect,#publish-mermaid-1787762378893-0 [data-look=\”neo\”].cluster rect,#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762378893-0 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762378893-0 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
React组件
类组件 Class Component
函数组件 Function Component
继承 React.Component
使用 this.state 管理状态
使用生命周期方法
纯函数形式
使用 Hooks 管理状态
使用 Hooks 处理副作用
二、类组件详解
2.1 类组件的定义与基本结构
类组件是使用ES6 class语法定义的React组件,它必须继承自React.Component或React.PureComponent。类组件通过render方法返回要渲染的内容。以下是一个简单的类组件示例:
import React, { Component } from 'react';
class Welcome extends Component {
constructor(props) {
super(props);
this.state = {
message: 'Hello, React!'
};
}
render() {
return (
<div>
<h1>{this.state.message}</h1>
<p>Welcome, {this.props.name}</p>
</div>
);
}
}
export default Welcome;
2.2 类组件的状态管理(state)
类组件通过this.state来管理组件的内部状态,使用this.setState()方法更新状态。状态更新是异步的,React会将多个setState调用合并为一次更新以提高性能。
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment = () => {
this.setState((prevState) => ({
count: prevState.count + 1
}));
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Add</button>
</div>
);
}
}
2.3 类组件的生命周期方法
类组件提供了丰富的生命周期方法,分为三个阶段:挂载、更新和卸载。通过流程图可以清晰展示完整的生命周期执行流程:
#publish-mermaid-1787762379129-1{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1787762379129-1 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762379129-1 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762379129-1 .error-icon{fill:#552222;}#publish-mermaid-1787762379129-1 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1787762379129-1 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1787762379129-1 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1787762379129-1 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1787762379129-1 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1787762379129-1 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1787762379129-1 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1787762379129-1 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1787762379129-1 .marker.cross{stroke:#333333;}#publish-mermaid-1787762379129-1 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1787762379129-1 p{margin:0;}#publish-mermaid-1787762379129-1 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1787762379129-1 .cluster-label text{fill:#333;}#publish-mermaid-1787762379129-1 .cluster-label span{color:#333;}#publish-mermaid-1787762379129-1 .cluster-label span p{background-color:transparent;}#publish-mermaid-1787762379129-1 .label text,#publish-mermaid-1787762379129-1 span{fill:#333;color:#333;}#publish-mermaid-1787762379129-1 .node rect,#publish-mermaid-1787762379129-1 .node circle,#publish-mermaid-1787762379129-1 .node ellipse,#publish-mermaid-1787762379129-1 .node polygon,#publish-mermaid-1787762379129-1 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762379129-1 .rough-node .label text,#publish-mermaid-1787762379129-1 .node .label text,#publish-mermaid-1787762379129-1 .image-shape .label,#publish-mermaid-1787762379129-1 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1787762379129-1 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1787762379129-1 .rough-node .label,#publish-mermaid-1787762379129-1 .node .label,#publish-mermaid-1787762379129-1 .image-shape .label,#publish-mermaid-1787762379129-1 .icon-shape .label{text-align:center;}#publish-mermaid-1787762379129-1 .node.clickable{cursor:pointer;}#publish-mermaid-1787762379129-1 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1787762379129-1 .arrowheadPath{fill:#333333;}#publish-mermaid-1787762379129-1 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1787762379129-1 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1787762379129-1 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762379129-1 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379129-1 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379129-1 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1787762379129-1 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1787762379129-1 .cluster text{fill:#333;}#publish-mermaid-1787762379129-1 .cluster span{color:#333;}#publish-mermaid-1787762379129-1 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1787762379129-1 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1787762379129-1 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1787762379129-1 .icon-shape,#publish-mermaid-1787762379129-1 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762379129-1 .icon-shape p,#publish-mermaid-1787762379129-1 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1787762379129-1 .icon-shape .label rect,#publish-mermaid-1787762379129-1 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379129-1 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1787762379129-1 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1787762379129-1 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node rect,#publish-mermaid-1787762379129-1 [data-look=\”neo\”].cluster rect,#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379129-1 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379129-1 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
组件挂载 Mounting
constructor
getDerivedStateFromProps
render
componentDidMount
组件更新 Updating
getDerivedStateFromProps
shouldComponentUpdate
render
getSnapshotBeforeUpdate
componentDidUpdate
组件卸载 Unmounting
componentWillUnmount
常用生命周期方法说明:
2.4 类组件的事件处理
类组件中事件处理需要注意this绑定问题。常见的绑定方式有以下几种:
class EventHandler extends Component {
constructor(props) {
super(props);
// 方式一:在构造函数中绑定
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Button clicked');
}
// 方式二:使用箭头函数(推荐)
handleToggle = () => {
console.log('Toggle clicked');
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click</button>
<button onClick={this.handleToggle}>Toggle</button>
{/* 方式三:在render中使用箭头函数 */}
<button onClick={() => this.handleClick()}>Inline</button>
</div>
);
}
}
2.5 类组件的Props使用
类组件通过this.props访问传入的属性。Props是只读的,组件不应修改自身的props。
class Greeting extends Component {
render() {
const { name, age } = this.props;
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
}
}
// 使用组件
// <Greeting name="Alice" age={25} />
三、函数组件详解
3.1 函数组件的定义与基本结构
函数组件是使用JavaScript函数定义的React组件,它接收props作为参数并返回JSX。函数组件没有this,无法使用state和生命周期(在Hooks出现之前)。以下是一个基本示例:
import React from 'react';
function Welcome(props) {
return (
<div>
<h1>Hello, {props.name}</h1>
</div>
);
}
// 箭头函数形式
const Greeting = ({ name }) => (
<div>
<h1>Hello, {name}</h1>
</div>
);
export default Welcome;
3.2 useState Hook状态管理
useState是React提供的Hook,让函数组件能够使用状态。它返回一个数组,包含当前状态值和更新状态的函数。
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '', age: 0 });
const increment = () => {
setCount(count + 1);
};
const updateUser = () => {
setUser(prev => ({ …prev, name: 'Bob' }));
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Add</button>
<button onClick={updateUser}>Update User</button>
</div>
);
}
3.3 useEffect Hook副作用处理
useEffect让函数组件能够执行副作用操作,相当于类组件中componentDidMount、componentDidUpdate和componentWillUnmount的组合。
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
// 相当于 componentDidMount 和 componentDidUpdate
useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
});
}, []); // 空数组表示只在挂载时执行
// 相当于 componentWillUnmount
useEffect(() => {
const timer = setInterval(() => {
console.log('Timer running');
}, 1000);
return () => {
clearInterval(timer);
};
}, []);
if (loading) return <div>Loading…</div>;
return <div>{JSON.stringify(data)}</div>;
}
3.4 其他常用Hooks介绍
React提供了多种内置Hooks,以下是一些常用Hooks的使用示例:
import React, {
useState,
useEffect,
useContext,
useReducer,
useCallback,
useMemo,
useRef
} from 'react';
// useContext: 访问Context
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button>Current theme: {theme}</button>;
}
// useReducer: 复杂状态管理
function todoReducer(state, action) {
switch (action.type) {
case 'add':
return […state, action.payload];
case 'remove':
return state.filter((_, i) => i !== action.index);
default:
return state;
}
}
function TodoList() {
const [todos, dispatch] = useReducer(todoReducer, []);
const addTodo = () => {
dispatch({ type: 'add', payload: 'New Todo' });
};
return (
<div>
<button onClick={addTodo}>Add Todo</button>
<ul>{todos.map((todo, i) => <li key={i}>{todo}</li>)}</ul>
</div>
);
}
// useCallback 和 useMemo: 性能优化
function OptimizedComponent({ data }) {
const [count, setCount] = useState(0);
const memoizedValue = useMemo(() => {
return data.map(item => item * 2);
}, [data]);
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Click</button>
</div>
);
}
3.5 函数组件的事件处理与Props
函数组件的事件处理更加简洁,无需考虑this绑定问题。Props直接作为函数参数传入。
function UserCard({ user, onUpdate }) {
const [editing, setEditing] = useState(false);
const handleSave = () => {
onUpdate(user.id);
setEditing(false);
};
return (
<div>
<h3>{user.name}</h3>
{editing ? (
<button onClick={handleSave}>Save</button>
) : (
<button onClick={() => setEditing(true)}>Edit</button>
)}
</div>
);
}
四、类组件与函数组件的区别
4.1 语法结构差异
类组件使用ES6 class语法,需要继承React.Component;函数组件使用普通函数或箭头函数定义。通过流程图对比两者结构:
#publish-mermaid-1787762379691-2{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1787762379691-2 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762379691-2 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762379691-2 .error-icon{fill:#552222;}#publish-mermaid-1787762379691-2 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1787762379691-2 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1787762379691-2 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1787762379691-2 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1787762379691-2 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1787762379691-2 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1787762379691-2 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1787762379691-2 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1787762379691-2 .marker.cross{stroke:#333333;}#publish-mermaid-1787762379691-2 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1787762379691-2 p{margin:0;}#publish-mermaid-1787762379691-2 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1787762379691-2 .cluster-label text{fill:#333;}#publish-mermaid-1787762379691-2 .cluster-label span{color:#333;}#publish-mermaid-1787762379691-2 .cluster-label span p{background-color:transparent;}#publish-mermaid-1787762379691-2 .label text,#publish-mermaid-1787762379691-2 span{fill:#333;color:#333;}#publish-mermaid-1787762379691-2 .node rect,#publish-mermaid-1787762379691-2 .node circle,#publish-mermaid-1787762379691-2 .node ellipse,#publish-mermaid-1787762379691-2 .node polygon,#publish-mermaid-1787762379691-2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762379691-2 .rough-node .label text,#publish-mermaid-1787762379691-2 .node .label text,#publish-mermaid-1787762379691-2 .image-shape .label,#publish-mermaid-1787762379691-2 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1787762379691-2 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1787762379691-2 .rough-node .label,#publish-mermaid-1787762379691-2 .node .label,#publish-mermaid-1787762379691-2 .image-shape .label,#publish-mermaid-1787762379691-2 .icon-shape .label{text-align:center;}#publish-mermaid-1787762379691-2 .node.clickable{cursor:pointer;}#publish-mermaid-1787762379691-2 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1787762379691-2 .arrowheadPath{fill:#333333;}#publish-mermaid-1787762379691-2 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1787762379691-2 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1787762379691-2 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762379691-2 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379691-2 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379691-2 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1787762379691-2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1787762379691-2 .cluster text{fill:#333;}#publish-mermaid-1787762379691-2 .cluster span{color:#333;}#publish-mermaid-1787762379691-2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1787762379691-2 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1787762379691-2 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1787762379691-2 .icon-shape,#publish-mermaid-1787762379691-2 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762379691-2 .icon-shape p,#publish-mermaid-1787762379691-2 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1787762379691-2 .icon-shape .label rect,#publish-mermaid-1787762379691-2 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762379691-2 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1787762379691-2 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1787762379691-2 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node rect,#publish-mermaid-1787762379691-2 [data-look=\”neo\”].cluster rect,#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379691-2 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762379691-2 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}函数组件 (Function Component)类组件 (Class Component)对应对应对应对应关键对比结果
代码量
类组件: 较多函数组件: 简洁
学习曲线
类组件: this绑定复杂函数组件: 更直观
性能
类组件: 较重函数组件: 更轻量
逻辑复用
类组件: HOC/Render Props函数组件: 自定义Hooks
未来趋势
React官方推荐函数组件 + Hooks
class Component extends React.Component
constructor初始化state和绑定方法
render方法返回JSX
生命周期方法
this.state / this.props通过this访问
挂载阶段componentDidMount
更新阶段componentDidUpdate
卸载阶段componentWillUnmount
错误处理componentDidCatch
执行副作用API调用/订阅
清理工作取消订阅/清除定时器
function Component props
直接返回JSX
Hooks函数
props参数直接访问
useState状态管理
useEffect副作用处理
useContext上下文访问
useReducer复杂状态逻辑
useCallback函数缓存
useMemo值缓存
useRefDOM引用/持久化
useLayoutEffectDOM同步副作用
自定义Hooks逻辑复用
三个生命周期合一挂载/更新/卸载
B3b的清理函数
4.2 状态管理方式对比
类组件使用this.state和this.setState管理状态;函数组件使用useState Hook。两者在状态更新上有明显差异:
// 类组件
class CounterClass extends Component {
state = { count: 0 };
increment = () => {
this.setState({ count: this.state.count + 1 });
};
}
// 函数组件
function CounterFunc() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
}
4.3 生命周期处理对比
类组件使用明确的生命周期方法,函数组件使用useEffect Hook统一处理。对比表格如下:
| 功能 | 类组件 | 函数组件 |
|——|——–|———-|
| 挂载后 | componentDidMount | useEffect(() => {}, []) |
| 更新后 | componentDidUpdate | useEffect(() => {}) |
| 卸载前 | componentWillUnmount | useEffect中return函数 |
| 应该更新 | shouldComponentUpdate | React.memo |
| 获取快照 | getSnapshotBeforeUpdate | 无直接对应 |
4.4 性能表现对比
函数组件在React 16.8之后通过Hooks优化,性能已与类组件相当甚至更优。主要差异如下:
4.5 适用场景对比
#publish-mermaid-1787762381019-3{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#publish-mermaid-1787762381019-3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762381019-3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#publish-mermaid-1787762381019-3 .error-icon{fill:#552222;}#publish-mermaid-1787762381019-3 .error-text{fill:#552222;stroke:#552222;}#publish-mermaid-1787762381019-3 .edge-thickness-normal{stroke-width:1px;}#publish-mermaid-1787762381019-3 .edge-thickness-thick{stroke-width:3.5px;}#publish-mermaid-1787762381019-3 .edge-pattern-solid{stroke-dasharray:0;}#publish-mermaid-1787762381019-3 .edge-thickness-invisible{stroke-width:0;fill:none;}#publish-mermaid-1787762381019-3 .edge-pattern-dashed{stroke-dasharray:3;}#publish-mermaid-1787762381019-3 .edge-pattern-dotted{stroke-dasharray:2;}#publish-mermaid-1787762381019-3 .marker{fill:#333333;stroke:#333333;}#publish-mermaid-1787762381019-3 .marker.cross{stroke:#333333;}#publish-mermaid-1787762381019-3 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#publish-mermaid-1787762381019-3 p{margin:0;}#publish-mermaid-1787762381019-3 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#publish-mermaid-1787762381019-3 .cluster-label text{fill:#333;}#publish-mermaid-1787762381019-3 .cluster-label span{color:#333;}#publish-mermaid-1787762381019-3 .cluster-label span p{background-color:transparent;}#publish-mermaid-1787762381019-3 .label text,#publish-mermaid-1787762381019-3 span{fill:#333;color:#333;}#publish-mermaid-1787762381019-3 .node rect,#publish-mermaid-1787762381019-3 .node circle,#publish-mermaid-1787762381019-3 .node ellipse,#publish-mermaid-1787762381019-3 .node polygon,#publish-mermaid-1787762381019-3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762381019-3 .rough-node .label text,#publish-mermaid-1787762381019-3 .node .label text,#publish-mermaid-1787762381019-3 .image-shape .label,#publish-mermaid-1787762381019-3 .icon-shape .label{text-anchor:middle;}#publish-mermaid-1787762381019-3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#publish-mermaid-1787762381019-3 .rough-node .label,#publish-mermaid-1787762381019-3 .node .label,#publish-mermaid-1787762381019-3 .image-shape .label,#publish-mermaid-1787762381019-3 .icon-shape .label{text-align:center;}#publish-mermaid-1787762381019-3 .node.clickable{cursor:pointer;}#publish-mermaid-1787762381019-3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#publish-mermaid-1787762381019-3 .arrowheadPath{fill:#333333;}#publish-mermaid-1787762381019-3 .edgePath .path{stroke:#333333;stroke-width:1px;}#publish-mermaid-1787762381019-3 .flowchart-link{stroke:#333333;fill:none;}#publish-mermaid-1787762381019-3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762381019-3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#publish-mermaid-1787762381019-3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762381019-3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#publish-mermaid-1787762381019-3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#publish-mermaid-1787762381019-3 .cluster text{fill:#333;}#publish-mermaid-1787762381019-3 .cluster span{color:#333;}#publish-mermaid-1787762381019-3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#publish-mermaid-1787762381019-3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#publish-mermaid-1787762381019-3 rect.text{fill:none;stroke-width:0;}#publish-mermaid-1787762381019-3 .icon-shape,#publish-mermaid-1787762381019-3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#publish-mermaid-1787762381019-3 .icon-shape p,#publish-mermaid-1787762381019-3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#publish-mermaid-1787762381019-3 .icon-shape .label rect,#publish-mermaid-1787762381019-3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#publish-mermaid-1787762381019-3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#publish-mermaid-1787762381019-3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#publish-mermaid-1787762381019-3 .node .neo-node{stroke:#9370DB;}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node rect,#publish-mermaid-1787762381019-3 [data-look=\”neo\”].cluster rect,#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node polygon{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].swimlane.cluster rect{filter:none;}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node path{stroke:#9370DB;stroke-width:1px;}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node .outer-path{filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node .neo-line path{stroke:#9370DB;filter:none;}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node circle{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].node circle .state-start{fill:#000000;}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].icon-shape .icon{fill:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762381019-3 [data-look=\”neo\”].icon-shape .icon-neo path{stroke:#9370DB;filter:drop-shadow(1px 2px 2px rgba(185, 185, 185, 1));}#publish-mermaid-1787762381019-3 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}是否是否是否
组件选择决策
是否需要复杂生命周期?
考虑类组件
是否是遗留项目?
保持现有类组件
优先使用函数组件
是否需要ErrorBoundary?
必须用类组件
可考虑重构为函数组件
使用Hooks管理状态和副作用
五、如何选择与最佳实践
5.1 何时使用类组件
虽然函数组件已成为主流,但以下场景仍需要使用类组件:
5.2 何时使用函数组件
推荐在以下场景使用函数组件:
5.3 类组件向函数组件迁移指南
迁移步骤如下:
// 迁移前:类组件
class UserProfile extends Component {
state = { user: null };
componentDidMount() {
fetchUser(this.props.userId).then(user => {
this.setState({ user });
});
}
render() {
if (!this.state.user) return <div>Loading…</div>;
return <div>{this.state.user.name}</div>;
}
}
// 迁移后:函数组件
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
if (!user) return <div>Loading…</div>;
return <div>{user.name}</div>;
}
