Skip to content

Instantly share code, notes, and snippets.

@rkatic
Last active June 29, 2023 18:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rkatic/943e0365ec1bc4a3a52e01beba3a3849 to your computer and use it in GitHub Desktop.
Save rkatic/943e0365ec1bc4a3a52e01beba3a3849 to your computer and use it in GitHub Desktop.
import { useEffect, useLayoutEffect, useRef, useState } from 'react'
function shallowEqualArrays(a, b) {
if (a.length !== b.length) {
return false
}
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) {
return false
}
}
return true
}
/*
A useMemo that ensures the result is not recalculated if provided dependencies did not change.
https://react.dev/reference/react/useMemo#caveats
*/
export const useMemoStable = (fn, deps) => {
const ref = useRef(null)
if (!ref.current || !deps || !shallowEqualArrays(ref.current.deps, deps)) {
ref.current = {
value: fn(),
deps: deps || [],
}
}
return ref.current.value
}
const defaultEnhance = ({ status, value, reason }) => ({
status,
value,
reason,
loading: status === 'pending',
ok: status === 'fulfilled',
data: value,
error: reason,
})
export const useAsyncMemo = (asyncFn, deps, enhance = defaultEnhance) => {
const curr = useMemoStable(() => ({
state: enhance({ status: 'pending' }),
}), deps)
const [, setDummyState] = useState()
useLayoutEffect(() => {
curr.aborter = new AbortController()
return () => curr.aborter.abort()
}, [curr])
useEffect(() => {
const { signal } = curr.aborter
Promise.allSettled([asyncFn({ signal })])
.then(([settled]) => {
if (!signal.aborted) {
curr.state = enhance(settled)
setDummyState([])
}
})
}, [curr])
return curr.state
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment