interface: add suspense utils

This commit is contained in:
Liam Fitzgerald 2021-06-29 12:21:14 +10:00
parent b0ed02f436
commit a25911319e
No known key found for this signature in database
GPG Key ID: D390E12C61D1CFFB
3 changed files with 79 additions and 0 deletions

View File

@ -0,0 +1,38 @@
export type SuspendState = 'result' | 'error' | 'pending';
export interface Suspender<T> {
read: () => T;
}
export function suspend<T>(awaiting: Promise<T>): Suspender<T> {
let state: SuspendState = 'pending';
let result: T | null = null;
const promise = awaiting
.then((res) => {
state = 'result';
result = res;
})
.catch((e) => {
state = 'error';
result = e;
});
return {
read: () => {
if (state === 'result') {
return result!;
} else if (state === 'error') {
throw result;
} else {
throw promise;
}
}
};
}
export function suspendWithResult<T>(result: T): Suspender<T> {
return {
read: () => result
};
}

View File

@ -539,3 +539,12 @@ export function binaryIndexOf(arr: BigInteger[], target: BigInteger): number | u
}
return undefined;
}
export async function jsonFetch<T>(info: RequestInfo, init?: RequestInit): Promise<T> {
const res = await fetch(info, init);
if(!res.ok) {
throw new Error('Bad Fetch Response');
}
const data = await res.json();
return data as T;
}

View File

@ -0,0 +1,32 @@
import React from 'react';
interface AsyncFallbackProps {
fallback?: JSX.Element;
}
class AsyncFallback extends React.Component<
AsyncFallbackProps,
{
error: boolean;
}
> {
constructor(props: AsyncFallbackProps) {
super(props);
this.state = { error: false };
}
componentDidCatch() {
this.setState({ error: true });
return false;
}
render() {
const { fallback, children } = this.props;
return (
<React.Suspense fallback={fallback}>
{this.state.error ? fallback : children}
</React.Suspense>
);
}
}
export default AsyncFallback;