react面试题:你知道useEffect 与 useLayoutEffect 有什么区别?

前言:自从react16.8推出hooks以来,hooks也被越来越多的人使用,面试中也不可避免的会被问到。那么hooks中的useEffect 与 useLayoutEffect 到底有什么区别呢?这个问题面试中经常会碰到,今天我们就来探究一下。

首先,我们来看下react官网中对此是怎么解释的:

使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同。

也就是说,useEffect 是异步执行的,而 useLayoutEffect 是同步执行的,会阻塞浏览器更新渲染。

那么,两个之间到底有什么区别呢?

1.相同点

在hooks的官方文档中对 useLayoutEffect 是这样定义的:

其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

那么我们来看下源码中是怎么定义这两个函数的:

useEffect(
   create: () => (() => void) | void,
   deps: Array<mixed> | void | null,
 ): void {
   currentHookNameInDev = 'useEffect';
   mountHookTypesDev();
   checkDepsAreArrayDev(deps);
   return mountEffect(create, deps);
 },

function mountEffect(
	  create: () => (() => void) | void,
	  deps: Array<mixed> | void | null,
	): void {
	  if (__DEV__) {
	    // $FlowExpectedError - jest isn't a global, and isn't recognized outside of tests
	    if ('undefined' !== typeof jest) {
	      warnIfNotCurrentlyActingEffectsInDEV(currentlyRenderingFiber);
	    }
	  }
	  return mountEffectImpl(
	    UpdateEffect | PassiveEffect | PassiveStaticEffect,
	    HookPassive,
	    create,
	    deps,
	  );
	} 

useLayoutEffect(
   create: () => (() => void) | void,
   deps: Array<mixed> | void | null,
 ): void {
   currentHookNameInDev = 'useLayoutEffect';
   mountHookTypesDev();
   checkDepsAreArrayDev(deps);
   return mountLayoutEffect(create, deps);
 },
 
function mountLayoutEffect(
	  create: () => (() => void) | void,
	  deps: Array<mixed> | void | null,
	): void {
	  return mountEffectImpl(UpdateEffect, HookLayout, create, deps);
        }

复制代码

可以看到两个函数最终调用的都是同一个名为 mountEffectImpl 的函数,入参一致,返回值也一致,所以函数签名是相同的。

至于到底使用哪一个,引用官网中说的一句话:我们推荐你一开始先用 useEffect,只有当它出问题的时候再尝试使用 useLayoutEffect。

2.区别

React 社区中最佳实践是这样的,大多数场景下可以直接使用 useEffect,但是如果你的代码引起了页面闪烁,也就是引起了组件突然改变位置、颜色及其他效果等的情况下,就推荐使用 useLayoutEffect 来处理。那么总结起来就是如果有直接操作 DOM 样式或者引起 DOM 样式更新的场景更推荐使用 useLayoutEffect。

总结一下:

它们的共同点很简单,底层的函数签名是完全一致的,都是调用的 mountEffectImpl ,在使用上没什么差异,基本可以直接替换,都是用于处理副作用。

那不同点就很大了,useEffect 在 React 的渲染过程中是被异步调用的,用于绝大多数场景,而 LayoutEffect 会在所有的 DOM 变更之后同步调用,主要用于处理 DOM 操作、调整样式、避免页面闪烁等问题。也正因为是同步处理,所以需要避免在 LayoutEffect 做计算量较大的耗时任务从而造成阻塞。

在未来的趋势上,两个 API 是会长期共存的,暂时没有删减合并的计划,需要开发者根据场景去自行选择。React 团队的建议非常实用,如果实在分不清,先用 useEffect,一般问题不大;如果页面有异常,再直接替换为 useLayoutEffect 即可。

参考:

  1. react中文网
  2. useEffect 与 useLayoutEffect 区别在哪里?
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享