首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 课程介绍
02 | React出现的历史背景及特性介绍
03 | 以组件方式考虑UI的构建
04 | JSX的本质 : 不是模板引擎,而是语法糖
05 | React组件的生命周期及其使用场景
06 | 理解Virtual DOM及key属性的作用
07 | 组件设计模式 : 高阶组件和函数作为子组件
08 | 理解新的Context API及其使用场景
09 | 使用脚手架工具创建React项目
10 | 打包和部署
11 | Redux(1) : 前端为何需要状态管理库
12 | Redux(2) : 深入理解Store、Action、Reducer
13 | Redux(3) : 在React中使用Redux
14 | Redux(4) : 理解异步Action、Redux中间件
15 | Redux(5) : 如何组织Action和Reducer
16 | Redux(6) : 理解不可变数据(Immutability)
17 | React Router(1):路由不只是页面切换,更是代码组织方式
18 | React Router(2):参数定义,嵌套路由的使用场景
19 | UI组件库对比和介绍:Ant.Design、Material UI、Semantic UI
20 | 使用Next.js创建React同构应用
21 | 使用Jest、Enzyme等工具进行单元测试
22 | 常用开发调试工具:ESLint、Prettier、React DevTool、Redux DevTool
23 | 前端项目的理想架构:可维护、可扩展、可测试、易开发、易建构
24 | 拆分复杂度(1):按领域模型(feature)组织代码,降低耦合度
25 | 拆分复杂度(2):如何组织component、action和reducer
26 | 拆分复杂度(3):如何组织React Router的路由配置
27 | 使用Rekit(1):创建项目,代码生成和重构
28 | 使用Rekit(2):遵循最佳实践,保持代码一致性
29 | 使用React Router管理登录和授权
30 | 实现表单(1):初始数据,提交和跳转
31 | 实现表单(2):错误处理,动态表单元素,内容动态加载
32 | 列表页(1):搜索,数据缓存和分页
33 | 列表页(2):缓存更新,加载状态,错误处理
34 | 页面数据需要来源多个请求的处理
35 | 内容页的加载与缓存
36 | 基于React Router实现分步操作
37 | 常见页面布局的实现
38 | 使用React Portals实现对话框,使用antd对话框
39 | 集成第三方JS库:以d3.js为例
40 | 基于路由实现菜单导航
41 | React中拖放的实现
42 | 性能永远是第一需求:时刻考虑性能问题
43 | 网络性能优化:自动化按需加载
44 | 使用Reselect避免重复计算
45 | 下一代React:异步渲染
46 | 使用Chrome DevTool进行性能调优&结课测试
当前位置:
首页>>
技术小册>>
深入学习React实战进阶
小册名称:深入学习React实战进阶
### 05 | React组件的生命周期及其使用场景 在React的广阔世界中,组件是构建用户界面的基石。理解React组件的生命周期(Lifecycle)对于高效、可维护的React应用开发至关重要。组件的生命周期是指一个组件从创建到销毁所经历的一系列阶段,React通过提供一系列的生命周期方法(Hooks之前的旧版React)或Hooks(React 16.8+引入),允许开发者在这些特定阶段插入代码,以实现复杂的逻辑和交互。本章节将深入探讨React组件的生命周期,包括旧版生命周期方法、Hooks的引入以及它们在不同使用场景下的应用。 #### 一、React组件生命周期概述 在React 16.8之前,组件的生命周期主要通过一系列的生命周期方法来表达,这些方法在组件的不同阶段被自动调用。主要可以分为三类:挂载(Mounting)、更新(Updating)、卸载(Unmounting)。 1. **挂载(Mounting)**:组件实例化并插入到DOM中的过程。 - `constructor(props)`:构造函数,用于初始化组件状态。 - `static getDerivedStateFromProps(props, state)`(类组件特有,用于替代`componentWillReceiveProps`):在实例化过程中和接收到新的props时调用,返回对象来更新state,或者返回null表示新的props不需要更新任何state。 - `render()`:唯一必须实现的方法,用于输出组件的UI。 - `componentDidMount()`:在组件挂载后立即调用,是进行DOM操作、网络请求等副作用操作的理想位置。 2. **更新(Updating)**:组件的props或state发生变化时,组件会重新渲染。 - `static getSnapshotBeforeUpdate(prevProps, prevState)`(类组件特有):在最新的渲染输出提交给DOM之前调用,允许你捕获一些信息(如滚动位置)并传递给`componentDidUpdate`。 - `shouldComponentUpdate(nextProps, nextState)`:在组件更新之前调用,返回一个布尔值决定组件是否应该重新渲染。默认返回true,但在优化性能时非常有用。 - `render()`:重新渲染组件。 - `getDerivedStateFromProps(props, state)`(再次提及,因可能在更新过程中被调用)。 - `componentDidUpdate(prevProps, prevState, snapshot)`:在更新发生后立即调用,适合执行依赖于DOM变更的操作。 3. **卸载(Unmounting)**:组件从DOM中移除的过程。 - `componentWillUnmount()`:在组件卸载及销毁之前直接调用。清理定时器、取消网络请求、移除事件监听器等副作用操作应在此方法中完成。 #### 二、Hooks引入后的生命周期变化 React 16.8引入了Hooks,旨在解决类组件的某些限制,并使得函数组件能够使用状态和其他React特性。Hooks并不直接对应传统的生命周期方法,但它们提供了在函数组件中执行类似操作的能力。 - **useEffect**:用于替代`componentDidMount`、`componentDidUpdate`和`componentWillUnmount`等生命周期方法。通过传入一个函数和一个依赖项数组,可以在组件挂载后、更新后执行副作用操作,并在组件卸载前进行清理。 - **useLayoutEffect**:类似于`useEffect`,但它在所有的DOM变更之后同步调用,适合需要读取DOM布局或执行重绘之前的操作。 #### 三、使用场景示例 ##### 1. 组件挂载后立即发起网络请求 在`componentDidMount`或`useEffect`中发起网络请求是常见的使用场景。这种方式确保了组件在挂载到DOM之后立即从服务器获取数据,从而避免了不必要的渲染。 ```jsx // 类组件示例 class MyComponent extends React.Component { componentDidMount() { fetchData().then(data => this.setState({ data })); } // ... } // 函数组件 + Hooks示例 function MyComponent() { const [data, setData] = useState(null); useEffect(() => { fetchData().then(data => setData(data)); }, []); // 空数组表示只在挂载时执行 // ... } ``` ##### 2. 根据props变化更新组件状态 在类组件中,你可能会使用`componentWillReceiveProps`或`getDerivedStateFromProps`来根据props的变化更新state。但推荐使用`getDerivedStateFromProps`,因为它更靠近渲染过程,并且避免了在即将卸载的组件上调用。 ```jsx // 类组件示例 static getDerivedStateFromProps(props, state) { if (props.value !== state.controlledValue) { return { controlledValue: props.value }; } return null; } // 函数组件通常不需要这样的逻辑,因为props可以直接在render中使用 ``` ##### 3. 性能优化:避免不必要的渲染 `shouldComponentUpdate`是性能优化的重要工具,它允许你基于当前和下一个props及state来决定组件是否需要更新。在函数组件中,虽然没有直接对应的生命周期方法,但可以通过React.memo和useMemo、useCallback等Hooks来优化。 ```jsx // 类组件示例 shouldComponentUpdate(nextProps, nextState) { // 逻辑判断 return this.props.id !== nextProps.id; } // 函数组件 + React.memo示例 const MyComponent = React.memo(function MyComponent(props) { // ... }, (prevProps, nextProps) => prevProps.id === nextProps.id); ``` ##### 4. 组件卸载前的清理工作 在组件卸载前,需要清理诸如定时器、事件监听器或取消网络请求等副作用。在类组件中,这通常在`componentWillUnmount`中完成。 ```jsx // 类组件示例 componentWillUnmount() { clearTimeout(this.timer); this.someEventListener.remove(); } // 函数组件 + useEffect示例 useEffect(() => { const timer = setTimeout(() => { // 逻辑 }, 1000); return () => { clearTimeout(timer); // 清理其他副作用 }; }, []); ``` #### 四、总结 React组件的生命周期是理解React组件行为的关键。无论是通过传统的生命周期方法还是现代的Hooks,掌握它们的使用场景和最佳实践对于构建高效、可维护的React应用至关重要。随着React版本的迭代,我们见证了从类组件到函数组件+Hooks的转变,这不仅简化了代码结构,也提供了更灵活、更强大的编程模式。深入理解这些概念,将帮助你更好地驾驭React的力量,开发出更加优秀的Web应用。
上一篇:
04 | JSX的本质 : 不是模板引擎,而是语法糖
下一篇:
06 | 理解Virtual DOM及key属性的作用
该分类下的相关小册推荐:
现代React前端开发实战
ReactJS面试指南
React全家桶--前端开发与实例(下)
React 进阶实践指南
React全家桶--前端开发与实例(上)
剑指Reactjs