useEffect和useLayoutEffect的区别

useEffect

基本上绝大多数的情况下使用useEffect就够了。需要注意的是useEffect的副作用调用不会阻塞dom元素的渲染,这和class组件componentDidMount或componentDidUpdate不同,componentDidMount或componentDidUpdate是dom更新后同步运行的,通常来说,如果不影响你的使用,useEffect这种运行方式有助于提高性能。

但是,如果你的副作用会导致dom元素的显示修改,这样会有两次dom修改,这时不应该使用useEffect,而应该使用useLayoutEffect。否则你会看到界面的修改产生闪动,通常会使用useLayoutEffect取代useEffect就是出于这种情况。

useLayoutEffect

useLayoutEffect和useEffect的使用方式完全一样。

useLayoutEffect的副作用调用在dom变更后马上发生,一般来说,如果你想在dom变更后测量一些dom元素的位置或者滚动条位置或者dom元素的样式后再设置新的dom显示,会使用useLayoutEffect。

这个运行的过程和componentDidMount或componentDidUpdate完全一样,代码会在dom更新后马上运行,这样允许你重新渲染一次dom。

总结

  • 如果dom更新后想通过更新后的dom属性再次渲染,使用useLayoutEffect。
  • 如果不需要dom更新或者dom更新无需被观测,则使用useEffect。

例子

useEffect的效果会产生一次闪烁,useLayoutEffect则没有刷新闪烁。

import React, { useState, useEffect, useLayoutEffect } from 'react';
import './index.less'

const random = () => {
  return 10 + Math.random() * 200
}

const App = () => {
  const [count1, setCount1] = useState(0);
  const [count2, setCount2] = useState(0);

  useEffect(() => {
    if (count1 === 0) {
      setCount1(random());
    }
  }, [count1]);

  useLayoutEffect(() => {
    if (count2 === 0) {
      setCount2(random());
    }
  }, [count2]);

  return (
    <div className="useLayoutEffect">
      <div onClick={() => setCount1(0)}>useEffect:{count1}</div>
      <div onClick={() => setCount2(0)}>useLayoutEffect:{count2}</div>
    </div>
  );
};

export default () => <App />;

查看效果

发表回复