首页 > 其他分享 >React中的Hooks---useEffect

React中的Hooks---useEffect

时间:2024-04-08 11:33:20浏览次数:19  
标签:--- return 函数 Hooks React 组件 const useEffect

简介

什么是React Hooks

React Hooks是在React 16.8版本中引入的一项重大特性,旨在解决函数组件在复杂场景下的状态管理和生命周期问题。

它们允许在不编写类组件的情况下使用state、生命周期方法等功能,使得函数组件更加简洁、易于理解和复用。

作为React Hooks的核心成员之一,useEffect在函数组件中扮演着处理副作用的重要角色。

它提供了统一、便捷的方式来组织和管理那些原本分散在生命周期方法中的非纯函数行为,极大地提升了代码的可读性和可维护性。

什么是 useEffect

在React中,副作用是指那些在渲染过程中不应直接执行,但与UI状态相关的操作。常见的副作用包括但不限于:

  • 数据获取:从服务器或缓存中获取数据。
  • 订阅与取消订阅:监听外部数据源(如WebSocket、Redux store等)的变化。
  • 更新DOM:直接操作DOM元素,如聚焦输入框、调整滚动位置等。
  • 设置与清除定时器:定期执行某些任务,如轮询检查数据更新、定时显示提示信息等。
  • 添加与移除事件监听器:监听窗口大小变化、键盘输入等事件,并在适当时候进行响应。

useEffect Hook就是用来封装这些副作用操作的。

它接受一个 “效应函数”(effect function)作为参数,在特定时机执行该函数以处理副作用。

此外,还可以通过第二个参数——依赖数组,控制useEffect的执行时机和清理机制。

使用 useEffect

基本结构

useEffect(() => {
  // 效应函数:在此处执行副作用操作
  // ...

  return () => {
    // 清除函数:在此处进行清理工作,如取消订阅、清除定时器等
    // ...
  };
}, [/* 依赖数组(可选) */]);
  • 效应函数:负责执行副作用操作。React会在组件渲染完成后(浏览器微任务队列清空后)调用此函数。

  • 清除函数(返回值):用于清理副作用,如取消订阅、清除定时器等。React会在下次 useEffect 执行前(或组件卸载时)调用此函数。

  • 依赖数组:一个可选的数组,指定 useEffect 所依赖的React状态变量或其他值。当数组中的某个值发生变化时,React将重新执行 useEffect 及其对应的清除函数。若省略此参数,则 useEffect 只会在组件挂载和卸载时各执行一次;若传入一个空数组 [],则只在DOM挂载的时候执行一次

useEffect 的执行时机

可以把 useEffect 看做 componentDidMount , componentDidUpdate , componentWillUnmount 这三个函数的组合。

当做 componentDidMount 和 componentDidUpdate 的时候

function App() {
    const [count,setCount] = useState(0);
    // 组件挂载完成之后 或 组件数据更新完成之后 执行
    useEffect(() => {
        console.log('组件挂载完成之后 或 组件数据更新完成之后 执行');
    })
    return (
        <div>
            {count}
            <button onClick={() => setCount(count + 1)}>+1</button>
        </div>
    )
}

仅当做 comonentDidMount 的时候

useEffect(() => {
    console.log('仅当做componentDidMount');
},[])

当做 componentWillunmount 的时候

注意:这里不是仅当做componentWillunmount

useEffect(() => () => {
    console.log('当做componentWillUnmount');
})

useEffect的使用方法示例

为window对象添加滚动事件

挂载完成后绑定事件,卸载组件后解除绑定

function App() {
    function onScroll() {
        console.log('监听到页面发生滚动了');
    }
    useEffect(() => {
        window.addEventListener('scroll',onScroll);
        return () => {
            // 卸载组件时解除对事件的绑定
            window.removeEventListener('scroll',onScroll);
        }
    })
    return (
        <div>
            App 
        </div>
    )
}

设置定时器让count数值每隔一秒增加1

function App() {
    
    const [count,setCount] = useState(0);
    useEffect(() => {
        const timeId = setInterval(() => {
           setCount(count => count + 1); 
        },1000)
        return () => {
            clearInterval(timeId);
        }
    },[])
    return (
        <div>
            <h1>当前求和为:{count}</h1> 
        </div>
    )
}

useEffect的第二个参数

只有指定数据发生变化的时候才触发effect

useEffect(() => {
    document.title = count;
}, [count]) 

如果第二个参数是一个空数组,就表明副效应参数没有任何依赖项。

因此,副效应函数这时只会在组件加载进入 DOM 后执行一次,后面组件重新渲染,就不会再次执行。

这很合理,由于副效应不依赖任何变量,所以那些变量无论怎么变,副效应函数的执行结果都不会改变,所以运行一次就够了。

useEffect结合异步函数

useEffect 中直接使用 asyncawait 是会报错的,推荐使用立即执行函数来包裹异步函数。

function getData() {
    return new Promise(resolve => {
        resolve({msg: 'Hello'})
    })
}
function App() {

    useEffect(() => {
        (async function () {
            const result = await getData();
            console.log(result);
        })()
    },[])
    
    return (
        <div>
            App
        </div>
    )
}

useEffect 的注意点

使用 useEffect() 时,有一点需要注意。如果有多个副效应,应该调用多个 useEffect() ,而不应该合并写在一起。

function App() {
  const [varA, setVarA] = useState(0);
  const [varB, setVarB] = useState(0);
  useEffect(() => {
    const timeoutA = setTimeout(() => setVarA(varA + 1), 1000);
    const timeoutB = setTimeout(() => setVarB(varB + 2), 2000);

    return () => {
      clearTimeout(timeoutA);
      clearTimeout(timeoutB);
    };
  }, [varA, varB]);

  return <span>{varA}, {varB}</span>;
}

上面的例子是错误的写法,副效应函数里面有两个定时器,它们之间并没有关系,其实是两个不相关的副效应,不应该写在一起。正确的写法是将它们分开写成两个 useEffect()

function App() {
  const [varA, setVarA] = useState(0);
  const [varB, setVarB] = useState(0);

  useEffect(() => {
    const timeout = setTimeout(() => setVarA(varA + 1), 1000);
    return () => clearTimeout(timeout);
  }, [varA]);

  useEffect(() => {
    const timeout = setTimeout(() => setVarB(varB + 2), 2000);

    return () => clearTimeout(timeout);
  }, [varB]);

  return <span>{varA}, {varB}</span>;
}

标签:---,return,函数,Hooks,React,组件,const,useEffect
From: https://www.cnblogs.com/guangdelw/p/18120764

相关文章

  • 实验一-密码引擎-3-加密API研究
    一、任务详情密码引擎API的主要标准和规范包括:1微软的CryptoAPI2RAS公司的PKCS#11标准3中国商用密码标准:GMT0016-2012智能密码钥匙密码应用接口规范,GMT0018-2012密码设备应用接口规范等研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提......
  • Python3.8-安装pip-autoremove
    pip-autoremove是一个Python第三方包管理工具扩展,它的作用是在移除指定Python包的同时,自动清理掉因该包而安装但目前已不再被任何其他包依赖的无用依赖项。pipinstallpip-autoremovepip-autoremovepyside2注意:需要将python安装目录的Scripts文件夹中的pip-autor......
  • 【随笔】Git 高级篇 -- 提交的技巧(上) rebase & commit --amend(十八)
    ......
  • Java零基础入门-String
    一、概述        近期有个小伙伴在看我的文章,说我在讲完基本类型,只是顺带提了一嘴String,然后说他的老师在课上对这String讲了足足一节课,好家伙,我觉得啊,这勾起了我的回忆,当初我看String的源码及知识点时,也是看了很久,这怪我,疏忽大意了啊。既然被这位小伙伴吐槽,那我就为......
  • Java零基础入门-多态
    一、概述        我之前上几期是教学了java类、及面向对象编程的三大基本特性,封装继承和多态。前一期,我是把继承大致讲了一遍,不知道你们对它有没有理解,何为继承,继承有啥好处,可以多继承嘛?等这类问题,我在上一期内容都有讲解,如果你们答不出来,没关系,你们可以再回去瞅瞅。......
  • 实验一-密码引擎-3-加密API研究
    一、任务详情密码引擎API的主要标准和规范包括:1微软的CryptoAPI2RAS公司的PKCS#11标准3中国商用密码标准:GMT0016-2012智能密码钥匙密码应用接口规范,GMT0018-2012密码设备应用接口规范等研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提交......
  • 实验一-密码引擎-3-加密API研究
    一、任务详情密码引擎API的主要标准和规范包括:1微软的CryptoAPI2RAS公司的PKCS#11标准3中国商用密码标准:GMT0016-2012智能密码钥匙密码应用接口规范,GMT0018-2012密码设备应用接口规范等研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代......
  • 密码引擎-3-加密API研究
    微软的CryptoAPI资料查询和学习微软公司在NT4.0以上版本中提供了一套完整的CryptoAPI的函数,支持密钥交换,数据加密解密,数字签名,给程序员带来了很大方便,用户在对软件进行保护的时候可以直接利用CryptoAPI来完成这些工作,比如计算注册码,检查程序的完整性等。在用这些API进行加密......
  • 20211314 实验一-密码引擎-3-加密API研究
    任务详情密码引擎API的主要标准和规范包括:1微软的CryptoAPI2RAS公司的PKCS#11标准3中国商用密码标准:GMT0016-2012智能密码钥匙密码应用接口规范,GMT0018-2012密码设备应用接口规范等研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用不同接口的代码,提交博客......
  • 实验一-密码引擎-加密API研究
    实验一-密码引擎-加密API研究密码引擎API的主要标准和规范包括:1微软的CryptoAPI2RAS公司的PKCS#11标准3中国商用密码标准:GMT0016-2012智能密码钥匙密码应用接口规范,GMT0018-2012密码设备应用接口规范等研究以上API接口,总结他们的异同,并以龙脉GM3000Key为例,写出调用......