首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01|身为Web前端工程师,我都在开发什么?
02|开发前端有哪些要点?React框架是如何应对的?
03|看板应用:从零开始快速搭建一个React项目
04|JSX:如何理解这种声明式语法糖?
05|前端组件化:如何将完整应用拆分成React组件?
06|虚拟DOM:为什么要关心React组件的渲染机制?
07|组件样式:聊聊CSS-in-JS的特点和典型使用场景
08|组件生命周期:React新老版本中生命周期的演化
09|React Hooks(上):为什么说在React中函数组件和Hooks是绝配?
10|React Hooks(下):用Hooks处理函数组件的副作用
11|事件处理:React合成事件是什么?为什么不用原生DOM事件?
12|组件表与里(上):数据是如何在 React 组件之间流转的?
13|组件表与里(下):用接口的思路设计开发React组件
14|现代化React:现代工程化技术下的React项目
15|不可变数据:为什么对React这么重要?
16|应用状态管理(上):应用状态管理框架Redux
17|应用状态管理(下):该用React组件状态还是Redux?
18|数据类型:活用TypeScript做类型检查
19|代码复用:如何设计开发自定义Hooks和高阶组件?
20|大型项目:源码越来越多,项目该如何扩展?
21|性能优化:保证优秀的用户体验
22|质量保证(上):每次上线都出Bug?你需要E2E测试
23|质量保证(下):测试金字塔与React单元测试
24|工程化与团队协作:让我们合作开发一个大型React项目
当前位置:
首页>>
技术小册>>
现代React前端开发实战
小册名称:现代React前端开发实战
### 10 | React Hooks(下):用Hooks处理函数组件的副作用 在React的旅程中,Hooks的引入无疑是一场革命,它允许我们在不编写类的情况下使用状态(state)和其他React特性。随着对Hooks的深入探索,我们不难发现,它们不仅简化了状态管理,还提供了强大的机制来处理函数组件中的副作用(side effects)。本章节将聚焦于React Hooks的“下半场”——特别是如何使用`useEffect`、`useLayoutEffect`等Hooks来优雅地处理函数组件的副作用,以及它们之间的区别和适用场景。 #### 一、理解副作用 在React中,副作用是指那些发生在渲染过程之外,但可能依赖于组件状态或属性的操作。例如,数据获取、订阅或手动更改DOM都属于副作用。在传统的类组件中,我们通常在`componentDidMount`、`componentDidUpdate`和`componentWillUnmount`等生命周期方法中处理这些操作。然而,在函数组件中,由于缺少这些生命周期方法,Hooks成为了处理副作用的关键工具。 #### 二、useEffect Hook `useEffect`是React中最常用的Hook之一,用于在函数组件中执行副作用操作。它接受一个函数作为参数(称为“effect”函数),该函数会在组件渲染到屏幕后执行。重要的是,`useEffect`中的effect函数会在组件的每次渲染后执行,但React提供了一种方式(通过依赖项数组)来优化这一行为,确保effect仅在相关依赖项改变时运行。 ##### 1. 基本用法 ```jsx import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); useEffect(() => { // 类似于componentDidMount和componentDidUpdate: document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } ``` 在这个例子中,每次组件渲染后,`useEffect`中的函数都会执行,更新文档的标题。然而,由于我们没有提供依赖项数组,这会导致在每次渲染后都执行,可能不是最优选择。 ##### 2. 依赖项数组 为了优化`useEffect`的执行,我们可以传递一个依赖项数组作为第二个参数。这样,只有当数组中的值发生变化时,effect函数才会重新执行。 ```jsx useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); // 只有当count改变时,effect才会重新运行 ``` ##### 3. 清理副作用 有时候,我们需要在组件卸载时或依赖项变化前执行一些清理操作(如取消订阅、移除事件监听器等)。`useEffect`允许我们返回一个函数,该函数将在组件卸载或effect重新运行之前执行。 ```jsx useEffect(() => { const subscription = someLibrary.subscribeToEvent(() => { // 处理事件 }); return () => { // 清理订阅 subscription.unsubscribe(); }; }, []); // 空数组表示effect仅在组件挂载时运行一次 ``` #### 三、useLayoutEffect Hook 尽管`useEffect`在大多数情况下都能满足需求,但在某些特定场景下,我们可能需要在所有DOM变更之后、浏览器进行任何绘制之前执行副作用。这就是`useLayoutEffect`的用武之地。 ##### 1. 与useEffect的区别 - **执行时机**:`useEffect`在浏览器绘制之后同步执行,而`useLayoutEffect`在浏览器绘制之前同步执行。 - **使用场景**:由于`useLayoutEffect`的同步性,它适用于读取DOM布局并同步重新渲染的场景,如调整元素尺寸或滚动位置。 - **性能考虑**:由于`useLayoutEffect`会在所有DOM变更后立即执行,过多地使用它可能会导致性能问题。 ##### 2. 示例 假设我们有一个组件,它需要根据其内容的尺寸来调整样式。使用`useLayoutEffect`可以确保在DOM更新后立即获取到正确的尺寸。 ```jsx import React, { useRef, useLayoutEffect } from 'react'; function ResizeObserverExample() { const ref = useRef(null); useLayoutEffect(() => { const observer = new ResizeObserver(entries => { for (let entry of entries) { console.log(entry.contentRect.width, entry.contentRect.height); } }); if (ref.current) { observer.observe(ref.current); } return () => { observer.disconnect(); }; }, []); // 仅在组件挂载时运行 return <div ref={ref}>Resize me!</div>; } ``` 在这个例子中,我们创建了一个`ResizeObserver`来监听元素尺寸的变化,并使用`useLayoutEffect`来确保在DOM更新后立即执行。 #### 四、总结 通过`useEffect`和`useLayoutEffect`,React为函数组件提供了强大的机制来处理副作用。`useEffect`适用于大多数需要异步操作或不影响DOM布局的副作用,而`useLayoutEffect`则适用于需要同步读取DOM布局并立即重渲染的场景。正确选择和使用这些Hooks,可以帮助我们编写出更加高效、可维护的React组件。 随着对React Hooks的深入理解,我们可以发现它们不仅仅是简单的状态管理工具,更是构建现代React应用的关键所在。通过合理利用Hooks,我们能够以更加声明式、函数式的方式编写React代码,享受更加灵活、强大的编程体验。
上一篇:
09|React Hooks(上):为什么说在React中函数组件和Hooks是绝配?
下一篇:
11|事件处理:React合成事件是什么?为什么不用原生DOM事件?
该分类下的相关小册推荐:
ReactJS面试指南
React全家桶--前端开发与实例(上)
React 进阶实践指南
深入学习React实战进阶
React全家桶--前端开发与实例(下)
剑指Reactjs