Skip to content

Instantly share code, notes, and snippets.

@bgmort
Last active August 9, 2024 22:21
Show Gist options
  • Save bgmort/97741f3b521c3f7b7491640d1daa8db4 to your computer and use it in GitHub Desktop.
Save bgmort/97741f3b521c3f7b7491640d1daa8db4 to your computer and use it in GitHub Desktop.
useMemoStable, a useMemo that you can count on to only run once per set of dependency values
import { useRef } from 'react'
/**
* This could also be called `useDerived`. Works like useMemo,
* except it guarantees that it only executes once per change of dependency values,
* which is what `useMemo` is often expected to do, but doesn't guarantee, and doesn't
* do in strict mode.
*
* Differs from `useEffect` in that the value is computed synchronously during render
*/
export function useMemoStable<T> (factory: () => T, deps: any[]) {
const valueRef = useRef<T>()
const depsRef = useRef<any[]>()
if (!deps) throw new Error('useMemoStable: missing dependency array')
if (!depsRef.current || !depsEqual(deps, depsRef.current)) {
// If dependencies have changed, compute new value and update references
valueRef.current = factory()
depsRef.current = deps
}
return valueRef.current as T
}
function depsEqual (deps: any[], prevDeps: any[]) {
if (deps.length !== prevDeps.length) return false
for (let i = 0; i < deps.length; i++) {
if (deps[i] !== prevDeps[i]) return false
}
return true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment