useLayoutEffect
与 useEffect
类似,与 useEffect
在浏览器 layout 和 painting 完成后异步执行 effect 不同的是,它会在浏览器布局 layout 之后,painting 之前同步执行 effect
useLayoutEffect
的执行时机对比如下:
import React, { useState, useEffect, useLayoutEffect } from 'react';
export default function LayoutEffect() {
const [width, setWidth] = useState('100px');
// useEffect 会在所有 DOM 渲染完成后执行 effect 回调
useEffect(() => {
console.log('effect width: ', width);
});
// useLayoutEffect 会在所有的 DOM 变更之后同步执行 effect 回调
useLayoutEffect(() => {
console.log('layoutEffect width: ', width);
});
return (
<>
<div id='content' style={{ width, background: 'red' }}>内容</div>
<button onClick={() => setWidth('100px')}>100px</button>
<button onClick={() => setWidth('200px')}>200px</button>
<button onClick={() => setWidth('300px')}>300px</button>
</>
);
}
// 使用 setTimeout 保证在组件第一次渲染完成后执行,获取到对应的 DOM
setTimeout(() => {
const contentEl = document.getElementById('content');
// 监视目标 DOM 结构变更,会在 useLayoutEffect 回调执行后,useEffect 回调执行前调用
const observer = new MutationObserver(() => {
console.log('content element layout updated');
});
observer.observe(contentEl, {
attributes: true
});
}, 1000);