useEffect 和 useLayoutEffect 的區別

繆宇發表於2019-12-01

在 React hook 中,useEffect 用來取代 componentDidMount 和 componentDidUpdate。主要作用是當頁面渲染後,進行一些副作用操作(比如訪問 DOM,請求資料)。

而 useLayoutEffect 的作用和 useEffect 幾乎差不多,你把你現有程式碼的 useEffect 全部替換成 useLayoutEffect,你幾乎看不到任何差別。

那它們的區別是什麼?看如下程式碼:

function App() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}
複製程式碼

11

執行上面的元件,點選div,頁面會更新一串隨機數。

當你連續點選時,你會發現這串數字在發生抖動。

原因在於,當你每次點選 div, count 會更新為 0, 之後 useEffect 內又把 count 改為一串隨機數。

所以頁面會先渲染成0,然後再渲染成隨機數,由於更新很快,所以出現了閃爍。

接下來我們將 useEffect 改為 useLayoutEffect:

function App() {
  const [count, setCount] = useState(0);
  
  useLayoutEffect(() => {
    if (count === 0) {
      const randomNum = 10 + Math.random()*200
      setCount(10 + Math.random()*200);
    }
  }, [count]);

  return (
      <div onClick={() => setCount(0)}>{count}</div>
  );
}
複製程式碼

22

閃爍消失了。

相比使用 useEffect,當你點選 div,count 更新為 0,此時頁面並不會渲染,而是等待 useLayoutEffect 內部狀態修改後,才會去更新頁面,所以頁面不會閃爍。

總結

  1. useLayoutEffect 相比 useEffect,通過同步執行狀態更新可解決一些特性場景下的頁面閃爍問題。
  2. useEffect 可以滿足百分之99的場景,而且 useLayoutEffect 會阻塞渲染,請謹慎使用。

Reference

When to useLayoutEffect Instead of useEffect