useOnceEffect
避免 React18 useEffect 运行两次
useOnceEffect 是 useEffect 的变体,保证 effect 回调只执行一次,即使在 React 18 的严格模式下(该模式在开发期间有意双重调用 effect)。它使用基于 WeakSet 的跟踪机制来检测并跳过重复调用。API 与 useEffect 完全相同——接受 effect 回调和可选的依赖数组。
使用场景
- 执行必须恰好运行一次的副作用(例如发送分析事件、初始化第三方库),且不能容忍 React 18 严格模式的双重触发
- 在启用
<StrictMode>的开发模式中防止重复的 API 调用 - 用更清洁的 API 替代手动的
useRef“已运行”防护
注意事项
- React 18 严格模式:在开发中,React 18 会挂载、卸载然后重新挂载组件以暴露不纯的 effect。
useOnceEffect通过在WeakSet中跟踪 effect 引用来防止第二次调用。 - 生产行为:在不发生严格模式双重调用的生产构建中,
useOnceEffect的行为与useEffect完全相同。 - 参见
useOnceLayoutEffect了解使用useLayoutEffect时序的相同行为,以及useMount了解更简单的仅挂载回调。
Usage
Live Editor
function Demo() { const [effect, setEffect] = useState(0); const [onceEffect, setOnceEffect] = useState(0); useOnceEffect(() => { setOnceEffect(onceEffect => onceEffect + 1); }, []); useEffect(() => { setEffect(effect => effect + 1); }, []); return ( <div> <div>onceEffect: {onceEffect}</div> <br /> <div>effect: {effect}</div> </div> ); };
Result