面试题持续更新。。。
useLayoutEffect 和 useEffect 的区别
这两个hook都是react用于模拟生命周期和监听属性更新的hook。区别在于使用场景和执行时机。
| hook | 使用场景 | 执行时机 |
|---|---|---|
| useLayoutEffect | 当需要使用Dom元素上的某些属性做操作时,可以使用useLayoutEffect,此时获取到的是dom生成后的dom属性 | dom生成之后,渲染更新之前 |
| useEffect | 更新不依赖于dom元素状态,适合用于获取数据、绑定事件监听器等,不影响页面渲染 | 页面渲染后,渲染线程空闲,准备下一次重绘前执行 |
哪个先执行?
useLayoutEffect 执行时机先于 useEffect
如果我给useEffect的函数设置async会报错吗?为什么?
会报错。因为如果给useEffect的dispatch函数设置为async状态,函数返回的是一个Promise,不符合react源码的调度定义。在使用useEffect时,会初始化effect链,通过调用dispatch函数,返回destory函数,用于销毁时执行,如果用async,返回就是一个Promise了。
源码层面分析
源码中使用useEffect或useLayoutEffect会执行一个mouseEffect的函数,然后会调用pushEffect,具体的话可以看着这篇文章:React 源码的状态管理
// 表示一个调用层级,实际代码并非如此组织
commitLayoutMountEffects_complete() {
commitLayoutEffectOnFiber() {
...
commitHookEffectListMount(
HookLayout | HookHasEffect,
finishedWork,
);
}
}
commitHookEffectListMount(flags: HookFlags, finishedWork: Fiber) {
// 当前effect对象的最后一个,react设置了成环
const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;
if (lastEffect !== null) {
const firstEffect = lastEffect.next;
let effect = firstEffect;
do {
// Mount
const create = effect.create;
// 调用的create也就是effect hook的第一个参数:函数。这里也体现了上面说为啥不能用async
effect.destroy = create();
} while(effect !== firstEffect)
}
}