React前端技术

React 源码探源 5 useEffect, useLayou

2021-07-04  本文已影响0人  吴摩西

背景

接上一章 React 源码探源 4 useState,来研究一下 useEffect 与 useLayoutEffect 相关的实现细节。

相关定义

先来看一下 React 相关的官方文档

  1. useEffect
    1. 作用:此 hook 主要是用来在组件渲染完成以后执行一些称为 effect 的操作,例如发送 ajax 请求,打点,当一些 state 发生变化以后,再更新其它的 state 等。
    2. 执行时机:useEffect 实在下次渲染之前执行,执行时浏览器已经对上次状态更新渲染完成。
    3. 返回值:useEffect可以返回一个回调函数,当组件 unMount 时,会被调用。
  2. useLayoutEffect
    1. 作用:如文档所示,绝大部分情况下都推荐使用 useEffect,只有使用 useEffect 的结果有些怪异时才会使用这个 hook。 笔者根据实验发现,只有更改 DOM 时导致了一些抖动的行为时使用 useLayoutEffect 时才会派上用场。
    2. 执行时机:useLayoutEffect 执行时,浏览器还未对 DOM 进行渲染。可以获取新的 DOM 进行操作。执行的时机较 useEffect 更早。
    3. 返回值:useLayoutEffect 也可以返回一个回调函数,也会在 unMount 时被调用。调用的时机也会较 useEffect 的回调更早。

示例代码

本次实例使用的详细代码如下

function Dev() {
  const [count, setCount] = React.useState(0);
  React.useEffect(function effectCb() {
    console.log('in effect');
    if (count === 1) {
      setCount(10);
    }
    return function effectUnMount() {
      console.log('effect unmount');
    };
  }, [count]);
  React.useLayoutEffect(function layoutEffectCb() {
    console.log('in layout effect', count);
    return function layoutEffectUnMount() {
      console.log('layout effect unmount');
    };
  }, [count]);
  return (<div id="div">
    <button id="btn" onClick={() => {
      setCount(function add(c) {return c + 1;});
    }}>click me</button>
    <div>the new text is <span>{count}</span></div>
  </div>);
}

详细流程

useEffect 和 useLayoutEffect 的详细流程

render

commit

effect 数据结构

可以看到以下的信息:

  1. useLayoutEffectuseEffect 生成的 hook 会跟useState生成的 hook 一起存储在 fiber 的 memorizedState 下面的链表里面。
  2. fiber 的 updateQueue 使用 lastEffect 存储着所有的 effect 生成的循环链表。
  3. hook 中的 memorizedStatelastEffect指向相同的地方,存储着 effect 的相关信息
    • create: effect 的回调函数
    • tag: 存储着 effect 的类型 Passive = 4标记着 useEffect LayoutStatic = 2 标记着 useLayoutEffect
    • destroy: effect 返回的回调函数
    • next: 下一个可能的 effect

unMount 过程

在组件卸载时,执行的顺序和机制与加载和更新时一致,只是在检查到 fiber 被删除时进行操作。

上一篇下一篇

猜你喜欢

热点阅读