Skip to content

Instantly share code, notes, and snippets.

@Grubba27
Last active March 13, 2023 21:31
Show Gist options
  • Save Grubba27/25fea366c118f459f7af5e3b9e1dcc78 to your computer and use it in GitHub Desktop.
Save Grubba27/25fea366c118f459f7af5e3b9e1dcc78 to your computer and use it in GitHub Desktop.
making any promise suspendable in react.
const cacheMap = new Map<string, Entry>()
interface Entry {
deps: EJSON[]
promise: Promise<unknown>
result?: unknown // here is what your T should be
error?: unknown
}
// you can use isEqual from lodash in this case
function arraysEqual<T>(a: T[], b: T[]): boolean {
if (a === b) return true;
if (a == null || b == null) return false;
if (a.length !== b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
function suspensify<T>(key: string, promise: Promise<T> | null, deps: DependencyList = [], lifespan = 0): T {
const cached = cacheMap.get(key)
useEffect(() =>
() => {
setTimeout(() => {
if (cached !== undefined && arraysEqual(cached.deps, deps)) cacheMap.delete(key)
}, lifespan)
}, [cached, key, ...deps])
if (promise === null) return null
if (cached !== undefined) {
if ('error' in cached) throw cached.error
if ('result' in cached) {
const result = cached.result as T
setTimeout(() => {
cacheMap.delete(key)
}, lifespan)
return result
}
throw cached.promise
}
const entry: Entry = {
deps,
promise: new Promise((resolve, reject) => { // here you work in your promise / waitable value. remember to set the result and error
promise
.then((result: any) => {
entry.result = result
resolve(result)
})
.catch((error: any) => {
entry.error = error
reject(error)
})
})
}
cacheMap.set(key, entry)
throw entry.promise
}
// usage
const usePlaceholders = () => {
const placeholders = fetch('https://jsonplaceholder.typicode.com/todos').then(x => x.json());
return suspensify('placeholders', placeholders);
}
function Placeholders() {
const placeholders = usePlaceholders();
return <pre>{ JSON.stringify(placeholders, null, 2) }</pre>;
}
function Example() {
return (
<Suspense fallback={ <div>Loader...</div> }>
{ <Placeholders/> }
</Suspense>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment