面试官:useLayoutEffect和useEffect的区别
hello,这里是潇晨,大家面试的过程中有没有遇到过这样的问题呢,useLayoutEffect和useEffect的区别是什么,大家可能会答复useEffect是异步的,useLayoutEffect是同步的,这样答复面试官真的会称心慢,咱们须要说分明他们在源码中的调用机会。
先来看个例子:点击触发更新之后,如果count之前的状态是0,咱们随机生成一个数字,在阻塞一段时间,在设置count位随机值,看看在useEffect和useLayoutEffect这两种状况下会有什么不同
import React, { useLayoutEffect, useState, useEffect } from "react";export default function App() { const [count, setCount] = useState(0); //用 useLayoutEffect 试试 useEffect(() => { if (count === 0) { const randomNum = Math.random() * 100;//随机生成一个数字 const now = performance.now(); while (performance.now() - now < 100) {//阻塞一段时间 console.log('blocking...'); } setCount(randomNum);//从新设置状态,设置成随机数 } }, [count]); return <div onClick={() => setCount(0)}>{count}</div>;}//在useEffect的状况下,一直点击触发更新,偶然会显示0//在useLayoutEffect的状况下,一直点击触发更新,不会偶现0
在源码中不论首次渲染还是更新的时候都会经验一个阶段叫commit阶段,这个阶段次要的工作就是解决一些钩子函数、生命周期、遍历render阶段造成的EffectList链表,将带有副作用的Fiber节点利用到实在节点上,如果对render阶段不理解能够参阅往期文章 render阶段 ,上面这张图是commit阶段源码的结构图,咱们具体的解说一下。
在commitRootImpl的函数中次要分三个局部:
- commit阶段前置工作
mutation阶段
- 调用commitBeforeMutationEffects,scheduleCallback调度执行flushPassiveEffects
- 调用commitMutationEffects,解决相干的副作用,操作实在节点useLayoutEffect的销毁函数在这个函数中执行
- 调用commitLayoutEffects,调用commitLayoutEffects的回调函数,这个时候副作用曾经利用到实在节点了,所以能拿到最新的节点。
- 在commit阶段完结之后flushPassiveEffects执行useEffect的销毁函数和回调函数。
- commit阶段收尾工作
所以useLayout/componentDidMount和useEffect的区别是什么?
答:他们在commit阶段不同机会执行,useEffect在commit阶段结尾异步调用,useLayout/componentDidMount同步调用
具体源码调试视频(高效学习):点击学习
往期react源码解析文章:
1.开篇介绍和面试题
2.react的设计理念
3.react源码架构
4.源码目录构造和调试
5.jsx&外围api
6.legacy和concurrent模式入口函数
7.Fiber架构
8.render阶段
9.diff算法
10.commit阶段
11.生命周期
12.状态更新流程
13.hooks源码
14.手写hooks
15.scheduler&Lane
16.concurrent模式
17.context
18事件零碎
19.手写迷你版react
20.总结&第一章的面试题解答