Created
February 8, 2024 23:49
-
-
Save akullpp/8ea817f67bcf485ff1690c28633c4da8 to your computer and use it in GitHub Desktop.
Deep compare version of useEffect for React
This file contains 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, useMemo, useRef } from 'react' | |
import { isEqual } from 'lodash-es' | |
type UseEffectParams = Parameters<typeof useEffect> | |
type EffectCallback = UseEffectParams[0] | |
type DependencyList = UseEffectParams[1] | |
type UseEffectReturn = ReturnType<typeof useEffect> | |
const isPrimitive = (val: unknown) => { | |
return val == null || /^[sbn]/.test(typeof val) | |
} | |
const checkDeps = (deps: DependencyList) => { | |
if (!deps || !deps.length) { | |
throw new Error('Use useEffect instead of useDeepEffect.') | |
} | |
if (deps.every(isPrimitive)) { | |
throw new Error('Use useEffect instead of useDeepEffect.') | |
} | |
} | |
/** | |
* @param value the value to be memoized (usually a dependency list) | |
* @returns a memoized version of the value as long as it remains deeply equal | |
*/ | |
const useDeepCompareMemoize = <T>(value: T) => { | |
const ref = useRef<T>(value) | |
const signalRef = useRef<number>(0) | |
if (!isEqual(value, ref.current)) { | |
ref.current = value | |
signalRef.current += 1 | |
} | |
return useMemo(() => { | |
return ref.current | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [signalRef.current]) | |
} | |
const useDeepEffect = (callback: EffectCallback, dependencies: DependencyList): UseEffectReturn => { | |
if (import.meta.env.DEV) { | |
checkDeps(dependencies) | |
} | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
return useEffect(callback, useDeepCompareMemoize(dependencies)) | |
} | |
export { useDeepEffect } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment