movie-web/src/hooks/useLoading.ts

47 lines
1.3 KiB
TypeScript
Raw Normal View History

2022-03-06 13:42:27 +01:00
import React, { useMemo, useRef, useState } from "react";
export function useLoading<T extends (...args: any) => Promise<any>>(
action: T
) {
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState<any | undefined>(undefined);
2022-03-06 13:42:27 +01:00
let isMounted = useRef(true);
// we want action to be memoized forever
const actionMemo = useMemo(() => action, []); // eslint-disable-line react-hooks/exhaustive-deps
React.useEffect(() => {
2022-03-06 13:42:27 +01:00
isMounted.current = true;
return () => {
2022-03-06 13:42:27 +01:00
isMounted.current = false;
};
}, []);
2022-03-06 13:42:27 +01:00
const doAction = useMemo(
() =>
async (...args: Parameters<T>) => {
setLoading(true);
setSuccess(false);
setError(undefined);
return new Promise((resolve) => {
actionMemo(...args)
.then((v) => {
if (!isMounted.current) return resolve(undefined);
setSuccess(true);
resolve(v);
})
.catch((err) => {
if (isMounted) {
setError(err);
setSuccess(false);
}
resolve(undefined);
});
}).finally(() => isMounted.current && setLoading(false));
},
[actionMemo]
);
return [doAction, loading, error, success];
}