引言
useEffect和useLayoutEffect是React官方推出的两个hooks,都是用来执行副作用的钩子函数,名字类似,功能相近,唯一不同的就是执行的时机有差异,今天这篇文章主要是从这两个钩子函数的执行时机入手,来剖析一下React的运行原理和浏览器的渲染流程。
官方解释
useLayoutEffect
其函数签名与 useEffect
相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前, useLayoutEffect
内部的更新计划将被同步刷新,尽可能使用标准的 useEffect
以避免阻塞视觉更新。
简单来讲,就是:useEffect是异步的,useLayoutEffect是同步的,异(同)步是相对于浏览器执行刷新屏幕Task来说的。
眼见为实
下面将通过一个简单的demo示例来说明具体的执行过程,其中React是16.13.1版本,首先是示例代码:
import React, { useState, useEffect, useLayoutEffect } from 'react';
const EffectDemo = () => {
const [count, setCount] = useState(0);
useEffect(function useEffectDemo() {
console.log('useEffect:', count);
}, [count]);
useLayoutEffect(function useLayoutEffectDemo() {
console.log('useLayoutEffect:', count);
}, [count]);
return (
<div>
<button
onClick={() => {
setCount(count + 1);
}}
>click me</button>
</div>
);
};
export default EffectDemo;
功能很简单,就不做界面展示,这里主要是看一下浏览器控制台Performance的监控图:
通过两个hooks的执行图可以看出,useLayoutEffect发生在页面渲染到屏幕(用户可见)之前,useEffect发生在那之后,中间还经历了DCL,FCP,FMP,LCP阶段,除开DCL(DomContentLoaded)之外,这些指标是RAIL模型衡量页面性能的标准,总的来说,渲染到屏幕的阶段是一个分水岭,那么渲染包含什么呢,还是看图吧:
此阶段完成了样式的计算(Recalculate Style)和布局(Layout),紧接着是一个Task,完成Update Layer Tree,Paint,Composite Layers,经过这一系列的任务后,页面最终呈现给用户,可以用一张图来表示浏览器的渲染过程:
后面会有相关学习资料,这里就不展开细说了。
模拟运行示例
在深入了解React的运行之前,首先在本地写一个简单的示例,大致模拟文章开始的例子:
<body>
<div id="app"></div>
<script type="text/javascript">
(function iife(){
function render() {
var appNode = document.querySelector('#app');
var textNode = document.createElement('span');
textNode.id = 'tip';
textNode.textContent = 'hello';
appNode.appendChild(textNode);
}
function useLayoutEffectDemo() {
console.log('useLayoutEffectDemo', document.querySelector('#tip'));
}
function useEffectDemo() {
console.log('useEffectDemo');
}
render();
useLayoutEffectDemo();
setTimeout(useEffectDemo, 0);
})();
</script>
</body>
然后启用Performance监控渲染情况:
总结一下: 1.首先运行render,完成后立即执行useLayoutEffectDemo函数(虽然已经插入DOM,但是界面还没有渲染出来); 2.注册异步回调函数useEffectDemo,该函数将在0ms过后加入EventLoop中的宏任务队列; 3.页面开始渲染:Recalculate Style->Layout->Update Layer Tree->Paint->Composite Layers->GPU绘制; 4.取出宏任务useEffectDemo,执行回调;
介绍到这里大家应该有了一个基本的认识了,如果想再继续深入了解执行机制,可查看 www.cnblogs.com/fulu/p/1347…