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 之后。
就像官网的介绍说的, useLayoutEffect 是 useEffect 的一个版本,在浏览器重新绘制屏幕之前触发。