React深入useEffect(上)

简介: 本文适合熟悉React、以及在用useEffect遇到难题的小伙伴进行阅读。

一、前言


本文基于开源项目:

https://github.com/facebook/react/blob/master/packages/react/src/ReactHooks.js

   最近有好友问广东靓仔:怎么写文章频率降低了?    


今年广东靓仔报名了软考,业余把精力更多投入到复习中。由于疫情影响,今天广州区暂停了软考上半年的相关科目,广东靓仔又来写文章了。


   广东靓仔将从三个方面来梳理useEffect相关内容:  

1、useEffect介绍  

2、useEffect原理    

3、useEffect源码解析    


相信有不少小伙伴在使用useEffect过程中遇到过不少问题,广东靓仔找来了几个有bug的例子:


例子一:

// 弹框显示触发定时器
useEffect(() => {
  timer = setInterval(() => {
    if (showModal) {
      requestFun()
    }
  }, 1000)
}, [showModal])  
// 关闭弹框,清除定时器
const closeModal = () => {
  clearInterval(timer)
}


弹框显示定时器开始执行,当关闭弹框。定时器居然没有清除,有bug


例子二:

useEffect(() => {
  let intervalId = setInterval(() => {
    fetchData();
  }, 1000 * 60);
  return () => {
    clearInterval(intervalId);
    intervalId = null;
  }
}, [])
const fetchData = () => {
   request({params}).then(ret => {
      if (ret.code === OK) {
          applyResult(ret.data);
      }
   })
}


经过一番操作后引用的值会调用上一次渲染的值,这是不对的


例子三:

当我们在useEffect调用第三方库的实例,然后在其他函数清除这个实例,发现无法清除。其他的小伙伴在用useEffect还遇到过其他的问题,这里就不一一展开,阅读完这篇文章后,一定会对useEffect有一个全面的理解。


二、useEffect介绍


    React16.8版本中描述了在 React 渲染阶段,改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作是不被允许的,因为可能会产生莫名其妙的 bug 并破坏 UI 的一致性。    因此在使用useEffect完成副作用操作,赋值给useEffect的函数会在组件渲染到屏幕之后执行。


useEffect一般是在每轮渲染结束后执行,当然我们也可以让它在只有某些值改变的时候才执行。


useEffect有个清除函数,官方demo如下:

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除订阅
    subscription.unsubscribe();
  };
});


一般在执行一些计时器或者订阅,我们会在组件卸载后,会清除这些内容。因此可以在清除函数里面做这些操作。


useEffect为防止内存泄漏,一般情况下如果组件多次渲染,在执行下一个effect 之前,上一个 effect 就已被清除。也就是说组件的每一次更新都会创建新的订阅。useEffect 的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。我们都知道一旦 effect 的依赖发生变化,它就会被重新创建,


例如:

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);


useEffect传递第二个参数,它是 effect 所依赖的值数组。只有当依赖改变后才会重新创建订阅。


温馨提示:有很多小伙伴在日常项目开发的时候,使用这个依赖的时候,很容易留下bug。比如:一个编辑弹框功能,如果useEffect依赖只写了个id,这个时候如果是对同一条数据进行编辑是不会再次执行useEffect的逻辑的。


三、useEffect原理


useEffect实际上是ReactCurrentDispatcher.current.useEffect(源码解析会讲到)

useEffect原理可以简单理解为:

  • 函数组件在挂载阶段会执行MountEffect,维护hook的链表,同时专门维护一个effect的链表。
  • 在组件更新阶段,会执行UpdateEffect,判断deps有没有更新,如果依赖项更新了,就执行useEffect里操作,没有就给这个effect标记一下NoHookEffect,跳过执行,去下一个useEffect。


我们都知道useEffect 在依赖变化时,执行回调函数。这个变化是指本次 render 和上次 render 时的依赖之间的比较。


默认情况下,effect 会在每轮组件渲染完成后执行,而且effect 触发后会把清除函数暂存起来,等下一次 effect 触发时执行,大概过程如下:


image.png


温馨提示:使用 hooks 要避免 if、for 等的嵌套使用

相关文章
|
2月前
|
前端开发 JavaScript
深入理解并实践React Hooks —— useEffect与useState
深入理解并实践React Hooks —— useEffect与useState
129 1
|
6月前
|
前端开发
React中useEffect的简单使用
React中useEffect的简单使用
|
12月前
|
前端开发 JavaScript
深入理解React中的useEffect钩子函数
深入理解React中的useEffect钩子函数
103 0
|
6月前
|
前端开发
React中useEffect、useCallBack、useLayoutEffect
React中useEffect、useCallBack、useLayoutEffect
|
2月前
|
前端开发
React中函数式Hooks之useEffect的使用
本文通过示例代码讲解了React中`useEffect` Hook的用法,包括模拟生命周期、监听状态和清理资源。
53 2
React中函数式Hooks之useEffect的使用
|
3月前
|
前端开发 JavaScript
介绍React中的useEffect
【8月更文挑战第6天】介绍React中的useEffect
35 2
|
4月前
|
存储 前端开发 API
useEffect问题之React提供了什么来帮助确保useEffect的依赖被正确指定
useEffect问题之React提供了什么来帮助确保useEffect的依赖被正确指定
|
4月前
|
前端开发 JavaScript 数据格式
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
react18【系列实用教程】Hooks (useState,useReducer,useRef,useEffect,useContext,useMemo,useCallback,自定义 Hook )
88 1
|
4月前
|
前端开发
react18【系列实用教程】Hooks 闭包陷阱 (2024最新版)含useState 闭包陷阱,useEffect 闭包陷阱,useCallback 闭包陷阱
react18【系列实用教程】Hooks 闭包陷阱 (2024最新版)含useState 闭包陷阱,useEffect 闭包陷阱,useCallback 闭包陷阱
65 0
|
4月前
|
JavaScript
react18【系列实用教程】useEffect —— 副作用操作 (2024最新版)
react18【系列实用教程】useEffect —— 副作用操作 (2024最新版)
34 0