JAVASCRIPT
Generic useAsync Hook for Managing Asynchronous Operations
Develop a flexible React `useAsync` hook to manage the lifecycle of any promise-based asynchronous operation, handling loading, success, and error states gracefully.
import { useState, useEffect, useCallback } from 'react';
function useAsync(asyncFunction, immediate = false) {
const [status, setStatus] = useState('idle');
const [value, setValue] = useState(null);
const [error, setError] = useState(null);
// The asyncFunction is wrapped in useCallback to prevent infinite loops
// if it's defined inline in the component using useAsync.
const execute = useCallback(async (...args) => {
setStatus('pending');
setValue(null);
setError(null);
try {
const response = await asyncFunction(...args);
setValue(response);
setStatus('success');
} catch (err) {
setError(err);
setStatus('error');
}
}, [asyncFunction]);
useEffect(() => {
if (immediate) {
execute();
}
}, [execute, immediate]);
return { execute, status, value, error };
}
// Example Usage:
// function DataFetcher() {
// const simulateDataFetch = () => {
// return new Promise((resolve, reject) => {
// setTimeout(() => {
// const success = Math.random() > 0.5;
// if (success) {
// resolve({ data: 'This is fetched data!' });
// } else {
// reject(new Error('Failed to fetch data.'));
// }
// }, 1500);
// });
// };
// const { execute, status, value, error } = useAsync(simulateDataFetch, true);
// return (
// <div>
// {status === 'idle' && <p>Ready to fetch data.</p>}
// {status === 'pending' && <p>Loading...</p>}
// {status === 'success' && <p>Data: {value.data}</p>}
// {status === 'error' && <p>Error: {error.message}</p>}
// <button onClick={execute} disabled={status === 'pending'}>
// Refetch Data
// </button>
// </div>
// );
// }
How it works: This `useAsync` hook is a powerful pattern for managing the state of any promise-based asynchronous operation within React components. It tracks `status` (idle, pending, success, error), `value` (the resolved data), and `error` (if the promise rejects). The `execute` function allows you to trigger the async operation. By using `useEffect` with an `immediate` flag, the operation can be run automatically on component mount. This hook centralizes async logic, making components cleaner and easier to manage by separating concerns.