system-praktyk-front/src/hooks/useAsync.ts
2020-11-06 20:03:14 +01:00

63 lines
1.9 KiB
TypeScript

import { useEffect, useState } from "react";
export type AsyncResult<T, TError = any> = {
isLoading: boolean,
value: T | undefined,
error: TError | undefined
};
export type AsyncState<T, TError = any> = [AsyncResult<T, TError>, (promise: Promise<T> | undefined) => void]
export function useAsync<T, TError = any>(supplier: Promise<T> | (() => Promise<T>) | undefined): AsyncResult<T, TError> {
const [isLoading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<TError | undefined>(undefined);
const [value, setValue] = useState<T | undefined>(undefined);
const [semaphore] = useState<{ value: number }>({ value: 0 })
const [promise, setPromise] = useState(typeof supplier === "function" ? null : supplier)
useEffect(() => {
setLoading(true);
setError(undefined);
setValue(undefined);
const myMagicNumber = semaphore.value + 1;
semaphore.value = myMagicNumber;
promise && promise.then(value => {
if (semaphore.value == myMagicNumber) {
setValue(value);
setLoading(false);
}
}).catch(error => {
console.error(error)
if (semaphore.value == myMagicNumber) {
setError(error);
setLoading(false);
}
})
}, [ promise ])
useEffect(() => {
if (typeof supplier === "function") {
setPromise(supplier());
} else {
setPromise(supplier);
}
}, [ supplier ])
return {
isLoading,
value,
error,
};
}
export function useAsyncState<T, TError = any>(initial: Promise<T> | undefined): AsyncState<T, TError> {
const [promise, setPromise] = useState<Promise<T> | undefined>(initial);
const asyncState = useAsync(promise);
return [ asyncState, setPromise ];
}