Implementing a Custom React Hook: useLoading
In application development, it's common to need a loading indicator during asynchronous operations like API requests. Consider a scenario where a user's VIP status is fetched asynchronously. Without a loading state, the UI might incorrectly show a non-VIP status initially, then switch to VIP once the data arrives. This kind of flickering negatively impacts the user experience. While managing this with a simple useState call like this:
const [loading, setLoading] = useState(false);
is possible, it becomes repetitive and cumbersome across multiple components. A better approach is to encapsulate this logic in a custom React Hook called useLoading.
Hook Signature
The goal is to pass in a request function and receive back both the loading state and a wrapped version of the function that automatically manages the loading state:
const [isLoading, wrappedRequest] = useLoading(fetchData);
Implementation
Here's the implementation of the hook using useState and useCallback:
import { useState, useCallback } from "react";
function useLoading(requestFn) {
const [isLoading, setIsLoading] = useState(false);
const wrappedRequest = useCallback(
(...args) => {
setIsLoading(true);
return requestFn(...args)
.then((response) => {
setIsLoading(false);
return response;
})
.catch((error) => {
setIsLoading(false);
return Promise.reject(error);
});
},
[requestFn]
);
return [isLoading, wrappedRequest];
}
Usage Example
Here's how you would use this hook in a component:
function VipStatusComponent() {
const [vipStatus, setVipStatus] = useState(null);
const [isLoading, fetchVipStatus] = useLoading(checkVipStatusApi);
useEffect(() => {
fetchVipStatus().then((data) => {
setVipStatus(data.vip);
}).catch((err) => {
console.error("Failed to fetch VIP status:", err);
});
}, [fetchVipStatus]);
return (
<div>
{isLoading ? (
<p>Loading...</p>
) : (
<p>{vipStatus ? "VIP User" : "Non-VIP User"}</p>
)}
</div>
);
}
Comparison with Alternatives
This hook provides a lightweight solution for managing loading states without the need for additional dependencies. However, for more complex data-fetching needs including caching, background refetching, and stale-while-revalidate patterns, libraires like React Query or utilities like AHooks offer more robust solutions.