React全家桶 - 【React】 - 【4】useEffect(概念、基础使用、不同依赖项说明、清除副作用)

一、useEffect

1.1 概念

  • useEffect 是一个 React Hook 函数,用于在 Recat 组件中 创建 不是由事件引起 而是 由渲染本身引起 的操作,比如 发送Ajax请求更改DOM等等;
  • 说明
    • 现在有个组件,里面有ittlearticle两块内容,如下图所示;
    • 左侧是没有渲染的样子,右侧是渲染完毕的样子;
    • 当渲染完毕之后,需要立马向服务器获取数据,渲染的整个过程是没有用户事件(比如:点击、滑动等等)参与的,我们需要等待一个时机,就是渲染完毕,完毕之后就立马去获取数据,这整个过程所表现的就是 由渲染本身引起 的操作;

1.2 基础使用

  • 需求

    • 当组件渲染完毕之后,立刻从服务器获取数据并显示到页面上;
  • 语法

    jsx 复制代码
    useEffect(() => {}, []);
    • 参数1
      • 函数 / 副作用函数
      • 函数内部 可以 放置 要执行的操作
    • 参数2
      • 可选参依赖项数组
      • 数组 里面 放置 依赖项,不同依赖项 会影响 第一个参数(函数) 的 执行
      • 当是一个 空数组 的时候,副作用函数 只会在 组件渲染 完毕之后 执行一次
  • 代码展示:

    jsx 复制代码
    import { 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也会执行;
  • 代码展示:

    jsx 复制代码
    import { 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 空数组依赖

  • 只在 组件 初始化 渲染时 执行 一次

  • 代码展示:

    jsx 复制代码
    import { 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 添加特定依赖项

  • 组件 初始化渲染 执行一次

  • 特定依赖项 发生变化 执行

  • 代码展示:

    jsx 复制代码
    import { 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的方式实现;
  • 普通方式:

    jsx 复制代码
    import { 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:

    jsx 复制代码
    import { 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(() => {
  // 发送网络请求
}, []);
  • 代码展示:
相关推荐
我认不到你8 分钟前
antd proFromSelect 懒加载+模糊查询
前端·javascript·react.js·typescript
集成显卡11 分钟前
axios平替!用浏览器自带的fetch处理AJAX(兼容表单/JSON/文件上传)
前端·ajax·json
scc214018 分钟前
spark的学习-06
javascript·学习·spark
焚琴煮鹤的熊熊野火19 分钟前
前端垂直居中的多种实现方式及应用分析
前端
我是苏苏39 分钟前
C# Main函数中调用异步方法
前端·javascript·c#
转角羊儿1 小时前
uni-app文章列表制作⑧
前端·javascript·uni-app
大G哥1 小时前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python
hong_zc1 小时前
初始 html
前端·html
小小吱1 小时前
HTML动画
前端·html
Bio Coder2 小时前
学习用 Javascript、HTML、CSS 以及 Node.js 开发一个 uTools 插件,学习计划及其周期
javascript·学习·html·开发·utools