import { useState } from "react";
/**
* A hook that returns a promise and its state.
*
* @param factory A function that returns a promise.
* @returns An object containing the promise's state and result.
* @example
* const { loading, result, error } = usePromise(() => fetch('https://example.com')
* .then(response => response.text())
* );
* if (loading) {
* return
Loading...
;
* }
* if (error) {
* return Error: {error.message}
;
* }
* return Result: {result}
;
*/
export function usePromise(factory: () => Promise) {
const init = () => {
const promise = factory();
if (!promise || typeof promise.then !== "function") {
throw new Error("The factory function must return a promise.");
}
return promise
.then(r => {
setResult(r);
setLoading(false);
return r;
})
.catch(e => {
setError(e);
setLoading(false);
throw e;
});
}
const [loading, setLoading] = useState(true);
const [result, setResult] = useState(undefined);
const [error, setError] = useState(undefined);
const [promise, setPromise] = useState(init);
const retry = () => {
setLoading(true);
setResult(undefined);
setError(undefined);
setPromise(init);
}
return { loading, result, error, promise, retry };
}
/**
* A hook that returns a promise and its state.
*/
export function usePromiseLazy(factory: (...args: Args) => Promise) {
const init = (promise: Promise) => {
if (!promise || typeof promise.then !== "function") {
throw new Error("The factory function must return a promise.");
}
return promise
.then(r => {
setResult(r);
setLoading(false);
return r;
})
.catch(e => {
setError(e);
setLoading(false);
throw e;
});
}
const [loading, setLoading] = useState(false);
const [result, setResult] = useState(undefined);
const [error, setError] = useState(undefined);
const [promise, setPromise] = useState | undefined>(undefined);
const execute = (...args: Args) => {
setLoading(true);
setResult(undefined);
setError(undefined);
setPromise(init(factory(...args)));
}
return [execute, { loading, result, error, promise }] as const;
}