useAsync
A hook that manages async operations with loading, success, and error states.
useAsync
The useAsync
hook provides a structured way to manage the lifecycle of asynchronous operations in React components. It handles loading states, success results, and error handling with a clean API that reduces boilerplate and helps prevent common async bugs like race conditions.
Installation
Install the useAsync hook using:
File Structure
API
Parameters
Prop | Type | Default |
---|---|---|
asyncFunction | (...args: P) => Promise<T> | Required |
initialState | Partial<AsyncState<T, E>> | { status: 'idle', value: null, error: null } |
Return Value
Prop | Type | Default |
---|---|---|
state | AsyncState<T, E> | - |
actions | AsyncActions<T, P> | - |
AsyncState
Prop | Type | Default |
---|---|---|
status | 'idle' | 'pending' | 'success' | 'error' | - |
value | T | null | - |
error | E | null | - |
AsyncActions
Prop | Type | Default |
---|---|---|
execute | (...args: P) => Promise<T | undefined> | - |
reset | () => void | - |
Examples
Form Submission
Using useAsync for form submission:
Multiple Async Operations
Managing multiple async operations in a single component:
Race Condition Prevention
The useAsync hook automatically prevents race conditions when multiple async calls are made in quick succession. It tracks the latest call and only updates the state for that call, ensuring older calls that complete later don’t overwrite newer results.
Use Cases
- API Requests: Handle fetch, axios, or other API calls
- Form Submissions: Manage submission states and responses
- Data Processing: Handle heavy data processing operations
- Authentication: Manage login, logout, and registration flows
- File Operations: Handle file uploads and downloads
- Animations: Manage complex animation sequences
- External Services: Interact with third-party services or APIs
- Database Operations: Handle database queries in client-side databases
Benefits
- Consistent State Management: Standardized approach for all async operations
- Race Condition Prevention: Handles overlapping async calls gracefully
- Type Safety: Fully typed with TypeScript for improved developer experience
- Reduced Boilerplate: Eliminates repetitive loading/error state management
- Clean Component Logic: Separates async logic from rendering logic
- Reusable: Can be used with any async function
- Flexible: Works with parameters, returns proper types, and supports error handling
Accessibility
When implementing async operations that affect the UI, consider these accessibility improvements:
- Use ARIA live regions to announce status changes to screen reader users
- Disable controls while operations are pending to prevent multiple submissions
- Provide clear error messages that identify the issue and suggest solutions
- Maintain focus appropriately after async operations complete
- Show loading states with both visual and text indicators
Error Handling
The useAsync hook captures errors thrown during the async function execution. To handle specific error types or status codes:
Best Practices
- Keep async functions outside component definitions when possible to prevent recreating them on every render
- Use useCallback for async functions defined inside components
- Initialize with appropriate initialState when you have default values
- Reset the state when necessary (e.g., when changing major parameters)
- Combine with other hooks like useEffect for auto-execution when dependencies change
- Consider extending the hook to include caching or retry mechanisms for specific use cases
- Provide fallback UI for each possible state (idle, pending, success, error)