[RFC] useLoading
Hook to track the loading state of async functions.
const [fn, loading] = useLoading(fn)
Example:
function Button({ onClick, children }) {
const [clickHandler, loading] = useLoading(onClick);
return <button onClick={clickHandler}>{loading ? "Loading..." : children}</button>;
}
Other Example:
function Form({ onSave }) {
const [handleSave, saving] = useLoading(onSave);
return (
<>
...
...
<button onClick={handleSave}>{saving ? "Saving..." : "Save"}</button>
</>
);
}
A posible implementation could look like this:
function useLoading(fn) {
const [loading, setLoading] = useState(false);
const _fn = useMemoizedFn(async (...args) => {
setLoading(true);
const result = await fn(...args);
setLoading(false);
return result;
});
return [_fn, loading];
}
what's the difference with useRequest
useLoading is not for data fetching, but for traking the loading state of any async function, the returned function can be hooked again in the component tree level. Like this:
async function doSomethingFor5Seconds() {
//...
}
// Parent Component
const [doSomething, doingIt] = useLoading(doSomethingFor5Seconds);
// Child Component
const [handleDo, inProgress] = useLoading(doSomething);
// SubChild Component
const [onClick, loading] = useLoading(handleDo);
// Remember the tuple is [Function, boolean] with any apropiate variable name
Currently using this approach, because it stucked loading forever on errors.
export default function useLoading<F extends (...args: any) => Promise<any>>(f: F): [F, boolean] {
const [loading, setLoading] = useState(false);
const _f = useMemoizedFn(async (...args: any) => {
setLoading(true);
try {
return await f(...args);
} catch (error) {
throw error;
} finally {
setLoading(false);
}
});
return [_f as any, loading];
}
useLoading is not for data fetching, but for traking the loading state of any async function
useRequest is not only for data fetching, but also can track the loading state of any async function
async function doSomethingFor5Seconds() {
//...
}
// manual trigger
const { loading, run } = useRequest(doSomethingFor5Seconds, {
manual: true
});
it stucked loading forever on errors.
useRequest manages the status of loading, error, users can handle different situations according to the status
const { error, loading } = useRequest(getUsername);
if (error) { ... }
if (loading) { ... }
Didn't know, but it is still looking to much verbose to rename variables and the word "request" in places where maybe there are not requests. But good to know.
I also think useLoading should exist
I also think the component DelayLoading will be better
Indeed!