Created
January 11, 2024 12:25
-
-
Save dovranJorayev/24c60437bb717fcb3d6dd37434299588 to your computer and use it in GitHub Desktop.
useEffect with empty deps that triggers once
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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