useOnceLayoutEffect
避免 React18 useLayoutEffect 运行两次
useOnceLayoutEffect 是 useLayoutEffect 的变体,保证 effect 回调只执行一次,即使在 React 18 的严格模式下(该模式在开发期间有意双重调用 effect)。它使用与 useOnceEffect 相同的基于 WeakSet 的跟踪机制,但以 useLayoutEffect 的时序运行——在 DOM 变更后同步执行,在浏览器绘制之前。
使用场景
- 执行必须在绘制前恰好发生一次的 DOM 测量或修改,不被 React 18 严格模式重复
- 初始化依赖布局的第三方库(例如图表或动画库,它们直接操作 DOM),如果初始化两次会出问题
- 任何需要
useLayoutEffect语义并保证单次执行的场景
注意事项
- 布局时序:在所有 DOM 变更后同步运行,在浏览器重绘之前。如果 effect 较慢,可能会阻塞视觉更新。
- React 18 严格模式:防止 React 18 在开发中为帮助检测副作用问题而执行的双重调用。
- 参见
useOnceEffect了解useEffect时序的等价物,以及useIsomorphicLayoutEffect了解 SSR 安全的布局 effect。
Usage
Live Editor
function Demo() { const [updateEffect, setLayoutEffect] = useState(0); const [onceLayoutEffect, setOnceLayoutEffect] = useState(0); useOnceLayoutEffect(() => { setOnceLayoutEffect(onceEffect => onceEffect + 1); }, []); useLayoutEffect(() => { setLayoutEffect(effect => effect + 1); }, []); return ( <div> <div>onceEffect: {onceLayoutEffect}</div> <br /> <div>effect: {updateEffect}</div> </div> ); };
Result