use-fetch-with-callbacks
Version:
A powerful React hook for HTTP requests with comprehensive callback support, request chaining, and TypeScript integration
318 lines (252 loc) • 8.15 kB
Markdown
A powerful React hook for HTTP requests with comprehensive callback support, request chaining, and TypeScript integration.
- 🔄 **Full HTTP Methods**: GET, POST, PUT, DELETE, PATCH with callback support
- 🔗 **Request Chaining**: Sequential operations with fluent API
- 📡 **Multiple Requests**: Concurrent requests to different endpoints
- ⏰ **Request Timeout**: Configurable timeout with automatic cancellation
- 🛑 **AbortController**: Automatic request cancellation on unmount
- 🎯 **TypeScript First**: Full type safety and IntelliSense support
- 📦 **Lightweight**: Zero dependencies except React
- 🔧 **Flexible**: Customizable headers, base URLs, and error handling
```bash
npm install use-fetch-with-callbacks
```
Explore live examples and comprehensive documentation in our **Storybook**:
[**🚀 View Live Examples →**](https://asudbury.github.io/use-fetch-with-callbacks)
Or run locally:
```bash
git clone https://github.com/asudbury/use-fetch-with-callbacks.git
cd use-fetch-with-callbacks
npm install
npm run storybook
```
- React 18.0.0 or higher
- TypeScript 4.0+ (for TypeScript projects)
```tsx
import useFetchWithCallbacks from 'use-fetch-with-callbacks';
interface User {
id: number;
name: string;
email: string;
}
const UserProfile = () => {
const { response, loading, error, fetchData, postData, deleteData } =
useFetchWithCallbacks<User>('/users/1', {
baseUrl: 'https://api.example.com',
headers: { Authorization: 'Bearer your-token' },
timeout: 5000, // 5 second timeout
});
const handleFetch = () => {
fetchData(
data => console.log('User loaded:', data),
error => console.error('Failed to load user:', error),
loading => console.log('Loading state:', loading)
);
};
const handleUpdate = () => {
postData(
{ name: 'John Doe', email: 'john@example.com' },
data => console.log('User updated:', data),
error => console.error('Update failed:', error)
);
};
const handleDelete = () => {
deleteData(
data => console.log('User deleted:', data),
error => console.error('Delete failed:', error)
);
};
return (
<div>
<button onClick={handleFetch}>Load User</button>
<button onClick={handleUpdate}>Update User</button>
<button onClick={handleDelete}>Delete User</button>
{loading && <p>Loading...</p>}
{error && <p>Error: {error.message}</p>}
{response && <p>Hello, {response.name}!</p>}
</div>
);
};
```
Execute multiple HTTP requests sequentially:
```tsx
const UserWorkflow = () => {
const { chain } = useFetchWithCallbacks<User>('/users/1', {
baseUrl: 'https://api.example.com',
});
const handleWorkflow = async () => {
// Execute a complex workflow
await chain()
.fetch(user => {
console.log('1. Fetched user:', user);
})
.patch(
{
lastLogin: new Date(),
},
updated => {
console.log('2. Updated login time:', updated);
}
)
.put(
{
status: 'active',
},
activated => {
console.log('3. Activated user:', activated);
}
)
.delete(deleted => {
console.log('4. Cleaned up:', deleted);
})
.then(finalResult => {
console.log('✅ Workflow completed:', finalResult);
})
.catch(error => {
console.error('❌ Workflow failed:', error);
})
.finally(() => {
console.log('🔄 Workflow finished');
})
.execute();
};
return <button onClick={handleWorkflow}>Run Workflow</button>;
};
```
Fetch from multiple endpoints simultaneously:
```tsx
const Dashboard = () => {
const { fetchMultipleData } = useFetchWithCallbacks<any>('/', {
baseUrl: 'https://api.example.com',
});
const loadDashboard = () => {
fetchMultipleData(
['/users', '/posts', '/comments'],
results => {
console.log('All data loaded:', results);
// results[0] = users, results[1] = posts, results[2] = comments
},
error => console.error('Failed to load dashboard:', error)
);
};
return <button onClick={loadDashboard}>Load Dashboard</button>;
};
```
```tsx
const api = useFetchWithCallbacks<ApiResponse>('/data', {
baseUrl: 'https://api.example.com',
headers: {
Authorization: 'Bearer token',
'Content-Type': 'application/json',
'X-Custom-Header': 'value',
},
timeout: 10000, // 10 second timeout
});
```
**Parameters:**
- `endpoint` (string): The API endpoint path
- `options` (UseFetchOptions): Optional configuration
**Returns:** `FetchResult<T>`
```typescript
interface FetchResult<T> {
response: T | null; // The response data
loading: boolean; // Loading state
error: Error | null; // Error state
requestCompleted: boolean; // Whether any request completed
fetchData: (...) => Promise<void>; // GET request
postData: (...) => Promise<void>; // POST request
putData: (...) => Promise<void>; // PUT request
deleteData: (...) => Promise<void>; // DELETE request
patchData: (...) => Promise<void>; // PATCH request
fetchMultipleData: (...) => Promise<void>; // Multiple concurrent requests
chain: () => ChainableRequest<T>; // Request chaining
}
```
```typescript
interface UseFetchOptions {
baseUrl?: string; // Base URL for all requests
headers?: HeadersInit; // Default headers
timeout?: number; // Request timeout (default: 10000ms)
}
```
```typescript
interface ChainableRequest<T> {
fetch: (...) => ChainableRequest<T>; // Add GET request to chain
post: (...) => ChainableRequest<T>; // Add POST request to chain
put: (...) => ChainableRequest<T>; // Add PUT request to chain
delete: (...) => ChainableRequest<T>; // Add DELETE request to chain
patch: (...) => ChainableRequest<T>; // Add PATCH request to chain
then: (callback) => ChainableRequest<T>; // Success callback
catch: (callback) => ChainableRequest<T>; // Error callback
finally: (callback) => ChainableRequest<T>; // Cleanup callback
execute: () => Promise<void>; // Execute the chain
}
```
The hook provides comprehensive error handling:
```tsx
const { fetchData } = useFetchWithCallbacks<User>('/users/1');
fetchData(
data => {
// Success callback
console.log('Success:', data);
},
error => {
// Error callback - handles network errors, timeouts, HTTP errors
if (error.message === 'Request timeout') {
console.log('Request timed out');
} else if (error.message.includes('404')) {
console.log('User not found');
} else {
console.log('Other error:', error.message);
}
}
);
```
Requests are automatically cancelled when:
- Component unmounts
- New request is initiated
- Timeout is reached
```tsx
const { fetchData } = useFetchWithCallbacks<User>('/users/1');
// This request will be cancelled if component unmounts
fetchData(
data => console.log('Success:', data),
error => console.log('Error:', error)
);
```
Full TypeScript support with proper type inference:
```tsx
interface User {
id: number;
name: string;
email: string;
}
// T is automatically inferred as User
const { response, fetchData } = useFetchWithCallbacks<User>('/users/1');
// response is typed as User | null
// fetchData callbacks receive properly typed data
```
MIT
Contributions are welcome! Please feel free to submit a Pull Request.
If you have any questions or need help, please open an issue on GitHub.
---
Made with ❤️ for the React community