ReactHook - useEffect

本文深入探讨了React中的useEffect钩子,解析其工作原理,包括如何处理副作用操作、定时器及监听器的添加与移除,并介绍了useEffect的保释机制以及如何避免因错误的state更新而导致的资源泄露。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

useEffect

作用:
  1. 推迟代码执行
    渲染完成之后再执行,常用于 数据读取

  2. 完成移除 - 组件卸载的时候做一些清理的工作
    例如:移除定时器、事件监听器等
    有关组件卸载:
    触发时机:当组件从 DOM 中移除时,会触发useEffect里返回的函数,useEffect里的内容不会执行,执行也没有意义了。当组件出现在DOM中时,会执行useEffect里的代码,useEffect里返回的函数不执行。

import React, { useState, useEffect } from 'react';

function TimerComponent() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prevCount => prevCount + 1);
    }, 1000);

    // 返回的函数将在组件卸载时执行
    return () => {
      clearInterval(timer);
      console.log('Timer cleared');
    };
  }, []); // 空依赖数组,effect 只在挂载和卸载时运行

  return <div>Timer: {count}</div>;
}

export default TimerComponent;

该行为是模拟了componentWillUnmount,常用于清理操作,例如取消网络请求、清除计时器或移除事件监听器。

补充:何时执行componentWillUnmount?

  • 组件从页面移除:当用户导航到另一个页面或条件渲染使得组件不再显示时,componentWillUnmount 会被调用。在上面的例子中,当 TimerComponent 被移除时,计时器会被清除。

  • 父组件卸载:如果父组件卸载了,所有子组件也会卸载,它们的 componentWillUnmount 也会被调用。

  1. 第二个参数来模拟生命周期。
    对于缓存的对象来说,因为每次函数都重新执行,因此对象的引用会变,所以useEffect第二个参数缓存的是引用的地址。

useEffect存在一种bail out(保释) / (补救)机制:

当你尝试设置相同的状态,仅仅让你把函数执行完,但不会再触发effect。

同理,在class组件中的setState也是一样。

setState

state设置重复的值 —— 只会重复渲染一次 +1


1. 推迟代码执行

例如:

上面其实本来就是一种错误的写法,只是React官方帮你兜了个底。

正确的做法是:
在这里插入图片描述

2. 完成移除 定时器、监听

function HOC() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        console.log('创建')
        return () => {
            console.log('销毁')
        }
    });
    return(
        <>
            <button onClick={() => setCount(count + 1)}>按钮</button>
        </>
    )
}
export default HOC;

当状态变化的时候,重新渲染,重新渲染导致useEffect执行(前提是没有依赖项)。在第一次刷新的时候,不执行useEffect返回的函数,只执行useEffect里的内容。后面状态变化导致重新渲染的时候,会优先执行useEffect返回的函数,然后再执行useEffect里的内容

例如:

页面初始化时:

第一次点击按钮时:


useEffect - clean-up阶段有两个:

  1. 删除组件
  2. 重新渲染当前组件
1. 第一个,删除组件的时候执行:

在这里插入图片描述

  • 注意:
    1. useEffect里的回调如果有返回值的话,必须是一个函数。
    2. 会先执行这个return函数,例如下面的代码。
2. 第二个,重新渲染的时候执行:

在这里插入图片描述

上面两种情景这样做的官方总结:

react官方:
1.必要性:极大的提升程序的可靠性
2.函数组件:简单、小型组件

程序可靠性
程序性能

结论:重新渲染的时候就先移除然后重新添加,目的是为了增强稳定性,如果有很庞大的初始化、移除操作,还应该用class(didMount、willUnmount)

注意:

错误的使用state,会导致资源泄露


例如:
1.某种异步操作开始——非常长
2.组件已经被卸载了
3.setState - 资源(内存泄露、socket泄露,主要是内存泄露)泄露

代码如下:
在这里插入图片描述

会报如下警告⚠️:

Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
in Unknown (at App.js:13)

解决方法:
在这里插入图片描述


3. 第三种, 第二个参数来模拟生命周期。

useEffect选择执行:
在这里插入图片描述
当a变化,才打印effect a;
当b变化,才打印effect b;

类似于 [a] 这种形式 官方叫做 ”跳过“

useEffect模拟生存周期函数:

useEffect(fn, [值]);

如:componentDidMount
在这里插入图片描述


useEffect() 的callback返回函数的case,其实是根据当前操作来的,是添加移除定时器还是添加移除dom,执行效果是不一样的,具体可以参考useEffect() 有始有终

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

. . . . .

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值