Skip to content

Instantly share code, notes, and snippets.

@dovranJorayev
Created January 11, 2024 12:25
Show Gist options
  • Save dovranJorayev/24c60437bb717fcb3d6dd37434299588 to your computer and use it in GitHub Desktop.
Save dovranJorayev/24c60437bb717fcb3d6dd37434299588 to your computer and use it in GitHub Desktop.
useEffect with empty deps that triggers once
import { useEffect, useRef, useState } from 'react';
type Noop = () => void;
export const useOnceEffect = (effect: Noop | { (): Noop }) => {
const effectFn = useRef<Noop | { (): Noop }>(effect);
const destroyFn = useRef<void | Noop>();
const effectCalled = useRef(false);
const rendered = useRef(false);
const [, setVal] = useState<number>(0);
if (effectCalled.current) {
rendered.current = true;
}
useEffect(() => {
// only execute the effect first time around
if (!effectCalled.current) {
destroyFn.current = effectFn.current();
effectCalled.current = true;
}
// this forces one render after the effect is run
setVal(val => val + 1);
return () => {
// if the comp didn't render since the useEffect was called,
// we know it's the dummy React cycle
if (!rendered.current) {
return;
}
// otherwise this is not a dummy destroy, so call the destroy func
if (destroyFn.current) {
destroyFn.current();
}
};
}, []);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment