一、useEffect
1.1 概念
useEffect
是一个 React Hook 函数,用于在 Recat 组件中 创建 不是由事件引起 而是 由渲染本身引起 的操作,比如 发送Ajax请求 、更改DOM等等;
- 说明 :
- 现在有个组件,里面有
ittle
、article
两块内容,如下图所示;- 左侧是没有渲染的样子,右侧是渲染完毕的样子;
- 当渲染完毕之后,需要立马向服务器获取数据,渲染的整个过程是没有用户事件(比如:点击、滑动等等)参与的,我们需要等待一个时机,就是渲染完毕,完毕之后就立马去获取数据,这整个过程所表现的就是 由渲染本身引起 的操作;
1.2 基础使用
-
需求 :
- 当组件渲染完毕之后,立刻从服务器获取数据并显示到页面上;
-
语法 :
jsxuseEffect(() => {}, []);
- 参数1 :
- 函数 / 副作用函数;
- 在 函数内部 可以 放置 要执行的操作;
- 参数2 :
- 可选参 ,依赖项数组;
- 在 数组 里面 放置 依赖项,不同依赖项 会影响 第一个参数(函数) 的 执行;
- 当是一个 空数组 的时候,副作用函数 只会在 组件渲染 完毕之后 执行一次;
- 参数1 :
-
代码展示:
jsximport { useState, useEffect } from 'react'; const url = 'http://geek.itheima.net/v1_0/channels'; const App = () => { const [list, setList] = useState([]); useEffect(() => { // 获取列表数据 async function getList() { // fetch 是 react 内置的 XMLHttpRequest对象 的 替代方案 const res = await fetch(url); const jsonRes = await res.json(); setList(jsonRes.data.channels || []); } getList(); }, []); return ( <div> <ul> {list.map((item) => { return <li key={item.id}>{item.name}</li>; })} </ul> </div> ); }; export default App;
-
关于
feach
更详细的内容,可以参考下面几位大佬的文章:
1.3 不同依赖项说明
useEffect
副作用函数的执行时机存在多种情况,根据 传入依赖项的不同,会有不同的执行表现;
依赖项 | 副作用函数执行实际 | ❗ 注意 |
---|---|---|
没有依赖项(不写第二个参数) | 组件初始渲染执行 + 组件更新时执行 | 任意 状态 更新 都会 执行 useEffect |
空数组依赖 | 只在组件初始渲染时执行一次 | 组件更新不执行 |
添加特定依赖项 | 组件初始渲染 + 特定依赖项变化时执行 | 特定依赖项 变化 才会执行 useEffect |
1.3.1 没有依赖项
-
组件 初始渲染时 执行一次;
-
组件 更新时 执行 ;
- 组件里面的状态变化,会导致组件的更新,所以状态变化,
useEffect
也会执行;
- 组件里面的状态变化,会导致组件的更新,所以状态变化,
-
代码展示:
jsximport { useEffect, useState } from 'react'; const App = () => { const [count, setCount] = useState(0); // 没有依赖项:组件初始渲染 + 组件更新 useEffect(() => { console.log('副作用函数执行了'); }); return ( <div> <h1>useEffect</h1> <button onClick={() => setCount(count + 1)}>{count}</button> </div> ); }; export default App;
-
演示:
1.3.2 空数组依赖
-
只在 组件 初始化 渲染时 执行 一次;
-
代码展示:
jsximport { useEffect, useState } from 'react'; const App = () => { const [count, setCount] = useState(0); // 空数组依赖:组件初始化渲染 useEffect(() => { console.log('副作用函数执行了'); }, []); return ( <div> <h1>useEffect</h1> <button onClick={() => setCount(count + 1)}>{count}</button> </div> ); }; export default App;
-
演示:
1.3.3 添加特定依赖项
-
组件 初始化渲染 执行一次;
-
特定依赖项 发生变化 执行;
-
代码展示:
jsximport { useEffect, useState } from 'react'; const App = () => { const [count, setCount] = useState(0); // 添加特定依赖项:组件初始化渲染 + 依赖项变化执行 useEffect(() => { console.log('副作用函数执行了'); }, [count]); return ( <div> <h1>useEffect</h1> <button onClick={() => setCount(count + 1)}>{count}</button> </div> ); }; export default App;
-
演示:
1.4 清除副作用
- 在
useEffect
中编写的 由渲染本身引起的对接组件外部的操作 ,社区也经常把它叫做 副作用操作 ,比如在useEffect
中开启了一个定时器,我们想在 组件卸载时 把这个定时器再清理掉,这个过程就是清理副作用; - 语法 :
- 说明 :
- 清除副作用的函数最常见的执行时机是在 组件卸载时 自动执行;
二、自定义Hoook
- 概念 :
- 自定义Hook是以
use
打头的函数 ,通过自定义Hook函数可以用来实现 逻辑 的 封装 和 复用;- 在App组件中,有一个div和按钮,点击按钮的时候,实现div的显示隐藏;
- 如果这个功能用的地方少,我们可以使用普通方式实现即可;
- 如果这个功能用的地方比较多,建议还是使用自定义Hook的方式实现;
-
普通方式:
jsximport { useState } from 'react'; const App = () => { // 若其他地方也要使用这个功能,定义状态和定义函数的代码需要重复书写,我们可以使用自定义Hook的方式实现逻辑的封装和复用 const [isShowDiv, setIsShowDiv] = useState(true); const toggle = () => { setIsShowDiv(!isShowDiv); }; return ( <div> {isShowDiv && <div>this is div</div>} <button onClick={toggle}>toggle</button> </div> ); }; export default App;
-
自定义Hook:
jsximport { useState } from 'react'; function useToggle() { // 可复用的代码逻辑 const [isShowDiv, setIsShowDiv] = useState(true); const toggle = () => { setIsShowDiv(!isShowDiv); }; // 注意:需要将其他组件使用的变量或函数return出去,供它们使用 // return [ isShowDiv, toggle ]; return { isShowDiv, toggle }; } const App = () => { // 使用自定义Hook的使用,直接调用hook函数,将需要的变量进行解构使用即可 // const [ isShowDiv, toggle ] = useToggle(); const { isShowDiv, toggle } = useToggle(); return ( <div> {isShowDiv && <div>this is div</div>} <button onClick={toggle}>toggle</button> </div> ); }; export default App;
- 封装自定义Hook通用思路 :
- 声明一个以
use
打头的函数;- 在函数体内封装可复用的逻辑(只要是可复用的逻辑都可以写在函数体内);
- 把组件中用到的状态或者回调
return
出去(以 数组 或 对象 的形式);
- 建议使用对象的形式,这样在解构的时候更加方便(数组解构需要对应顺序);
- 在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用;
三、React Hook 使用规则
以下规则都是针对以
use
打头的Hook函数;
- 只能在 组件中 或者其他 自定义Hook函数中 调用;
- 只能在 组件的顶层被调用 ,不能嵌套在
if、for
语句中或其他函数(非自定义Hook函数)中; - 若没有遵守以上规则,就会报错;
四、案例展示 - B站评论 - 使用useEffect获取数据
- 需求:
- 使用请求接口的方式获取评论列表并渲染;
- 使用自定义Hook函数封装数据请求的逻辑;
- 准备工作:
- 使用
json-serve
工具模拟接口服务,通过axios
发送接口请求;json-serve
是一个快速以.json
文件作为数据源模拟接口服务的工具;axios
是一个广泛使用的前端请求库;- 使用
useEffect
调用接口获取数据
jsx// useEffect 传入空依赖的时候,只会在组件初始化的时候执行一次 useEffect(() => { // 发送网络请求 }, []);
- 代码展示: