useOnceEffect
A Hook that avoids React18 useEffect run twice
useOnceEffect is a variant of useEffect that guarantees the effect callback executes only once, even under React 18’s Strict Mode which intentionally double-invokes effects during development. It uses a WeakSet-based tracking mechanism to detect and skip duplicate invocations. The API is identical to useEffect — it accepts an effect callback and an optional dependency array.
When to Use
- Performing side effects that must run exactly once (e.g., sending an analytics event, initializing a third-party library) and cannot tolerate React 18 Strict Mode double-firing
- Protecting against duplicate API calls on mount in development mode with
<StrictMode>enabled - Replacing manual
useRef-based “already ran” guards with a cleaner API
Notes
- React 18 Strict Mode: In development, React 18 mounts, unmounts, and re-mounts components to surface impure effects.
useOnceEffectprevents the second invocation by tracking the effect reference in aWeakSet. - Production behavior: In production builds where Strict Mode double-invocation does not occur,
useOnceEffectbehaves identically touseEffect. - See also
useOnceLayoutEffectfor the same behavior usinguseLayoutEffecttiming, anduseMountfor a simpler mount-only callback.
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