Learn React Hooks -- useLayoutEffect

81 阅读1分钟

useLayoutEffect

借用一个案例搞懂 useLayoutEffect

import { useLayoutEffect, useEffect, useState } from 'react';

const userIds = [1, 2];

const Demo = () => {
  const [userId, setUserId] = useState(userIds[0]);
  const [isAdmin, setIsAdmin] = useState(false);

  // This artificially slows down rendering
  let now = performance.now();
  while (performance.now() - now < 200) {
    // Do nothing for a bit...
  }
  console.log('render');

  useEffect(() => {
    console.log('paint done');
  });

  // useLayoutEffect(() => {
  //   setIsAdmin(userId === userIds[0]);
  //   console.log('isAdmin change, trigger');
  // }, [userId]);

  useEffect(() => {
    setIsAdmin(userId === userIds[0]);
    console.log('isAdmin change, trigger');
  }, [userId]);

  const handleChange = () => {
    const otherId = userIds.find((id) => id !== userId)!;
    setUserId(otherId);
    console.log('userId change, trigger');
  };

  return (
    <div className="tutorial-shorts">
      <p>userId: {userId}</p>
      <p>Admin: {isAdmin ? 'true' : 'false'}</p>
      <button onClick={handleChange}>Change User</button>
    </div>
  );
};

export default Demo;
  • 使用 useLayoutEffect 时, userId 和 isAdmin 总是同时更新

    userId change, trigger
    render
    isAdmin change, trigger
    paint done
    render
    paint done
    
  • 使用 useEffect 时,isAdmin 总是在useId更新后再更新

    userId change, trigger
    render
    paint done
    isAdmin change, trigger
    ender
    paint done
    

可以看到两次实验的第一次 paint done 时机不一样,使用 useEffect 时每次paint 都在 trigger 之后,而使用useLayoutEffect 时,第一次 paint 出现在 两次 trigger 之后。

就像官网的介绍说的, useLayoutEffectuseEffect 的一个版本,在浏览器重新绘制屏幕之前触发。