How to handle an async calculation
This example demonstrates how to handle an async calculation using the useAsync
hook.
tsx
import {useAsync} from './useAsync';
const calculateOperationStats = async () => {
return new Promise<{ total: number; average: number; highest: number }>(
(resolve) => {
const operations = Array.from({length: 100000}, () =>
Math.floor(Math.random() * 1000)
);
setTimeout(() => {
const total = operations.reduce((sum, value) => sum + value, 0);
const average = total / operations.length;
const highest = Math.max(...operations);
resolve({total, average, highest});
}, 2000); // Simulate an expensive calculation
}
);
};
export default function App() {
const {execute, data, isLoading, error, isSuccess} = useAsync<{
total: number;
average: number;
highest: number;
}>();
return (
<div>
<button
onClick={() => execute(calculateOperationStats)}
disabled={isLoading}
>
{isLoading ? 'Calculating...' : 'Calculate Stats'}
</button>
{isLoading && <p>Calculating statistics for 100,000 operations...</p>}
{error && <p>Error: {error.message}</p>}
{isSuccess && data && (
<div>
<p>Statistics:</p>
<ul>
<li>Total: {data.total}</li>
<li>Average: {data.average.toFixed(2)}</li>
<li>Highest Value: {data.highest}</li>
</ul>
</div>
)}
</div>
);
};
typescript
import {useState, useCallback} from 'react';
interface UseAsyncState<T> {
data: T | null;
isLoading: boolean;
error: Error | null;
isSuccess: boolean;
}
export const useAsync = <T>() => {
const [state, setState] = useState<UseAsyncState<T>>({
data: null,
isLoading: false,
error: null,
isSuccess: false
});
const execute = useCallback(async (asyncFunction: () => Promise<T>) => {
setState((prev) => ({...prev, isLoading: true, error: null}));
try {
const result = await asyncFunction();
setState({
data: result,
isLoading: false,
error: null,
isSuccess: true
});
return result;
} catch (error) {
setState({
data: null,
isLoading: false,
error: error as Error,
isSuccess: false
});
throw error;
}
}, []);
return {execute, ...state};
};