React Download File Within Handler
React File Download: A Complete Guide 📥
A clean, reusable solution for downloading files from URLs in React applications
The Core Function
Here’s a robust file download utility that handles most common scenarios:
export default async function downloadFileFromUrl(url, defaultName, headers, onFinish) {
const response = await fetch(url, {
method: 'GET',
headers: headers || {}
});
const contentDisposition = response.headers.get('Content-Disposition');
const filename = contentDisposition
? contentDisposition.split('filename=')[1]
: defaultName;
if (response.ok) {
const blob = await response.blob();
// Create blob link to download
const blobUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobUrl;
link.download = filename;
// Force download
link.click();
} else {
const message = `Error Message: ${response.statusText}`;
handleError(message);
}
if (onFinish) {
onFinish();
}
}
How It Works
1. Fetch the File
- Makes a GET request to the provided URL
- Supports custom headers for authentication or other requirements
2. Smart Filename Detection
- Attempts to extract filename from
Content-Disposition
header - Falls back to provided
defaultName
if header is missing
3. Blob Download
- Converts response to blob for binary data handling
- Creates a temporary object URL
- Programmatically triggers download via hidden link
4. Cleanup & Callback
- Handles errors gracefully
- Executes optional completion callback
Usage Examples
Basic Download
await downloadFileFromUrl(
'https://api.example.com/files/report.pdf',
'quarterly-report.pdf'
);
With Authentication
await downloadFileFromUrl(
'https://api.example.com/files/private-doc.pdf',
'document.pdf',
{ 'Authorization': 'Bearer your-token-here' }
);
With Loading State
const [downloading, setDownloading] = useState(false);
const handleDownload = async () => {
setDownloading(true);
await downloadFileFromUrl(
fileUrl,
'my-file.pdf',
null,
() => setDownloading(false) // onFinish callback
);
};
Possible Extensions
1. Enhanced Error Handling
// Add more specific error types
if (!response.ok) {
switch (response.status) {
case 404:
throw new Error('File not found');
case 403:
throw new Error('Access denied');
case 500:
throw new Error('Server error');
default:
throw new Error(`Download failed: ${response.statusText}`);
}
}
2. Progress Tracking
// Add download progress callback
export default async function downloadFileFromUrl(
url,
defaultName,
headers,
onFinish,
onProgress // New parameter
) {
const response = await fetch(url, { method: 'GET', headers: headers || {} });
if (!response.ok) throw new Error('Download failed');
const contentLength = response.headers.get('Content-Length');
const total = parseInt(contentLength, 10);
let loaded = 0;
const reader = response.body.getReader();
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
loaded += value.length;
if (onProgress && total) {
onProgress({ loaded, total, percentage: (loaded / total) * 100 });
}
}
const blob = new Blob(chunks);
// Continue with download logic...
}
3. File Type Validation
// Add MIME type checking
const validateFileType = (response, allowedTypes = []) => {
const contentType = response.headers.get('Content-Type');
if (allowedTypes.length && !allowedTypes.includes(contentType)) {
throw new Error(`Invalid file type: ${contentType}`);
}
};
4. Memory Management
// Clean up blob URL to prevent memory leaks
const blobUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = blobUrl;
link.download = filename;
link.click();
// Clean up
setTimeout(() => {
window.URL.revokeObjectURL(blobUrl);
}, 1000);
5. Custom Hook Version
// useFileDownload hook
const useFileDownload = () => {
const [downloading, setDownloading] = useState(false);
const [error, setError] = useState(null);
const download = useCallback(async (url, defaultName, headers) => {
try {
setDownloading(true);
setError(null);
await downloadFileFromUrl(url, defaultName, headers);
} catch (err) {
setError(err.message);
} finally {
setDownloading(false);
}
}, []);
return { download, downloading, error };
};
Common Use Cases
- API File Downloads: PDFs, Excel reports, images from secured endpoints
- Document Management Systems: Download user files with proper authentication
- Export Features: Download generated reports or data exports
- Media Downloads: Images, videos, audio files
Browser Compatibility
This approach works in all modern browsers that support:
- Fetch API
- Blob API
- Object URLs
- HTML5 download attribute
For older browsers, consider adding polyfills or fallback methods.
Best Practices
- Always handle errors - Network requests can fail
- Show loading states - File downloads can take time
- Validate file types - Ensure security and user expectations
- Clean up resources - Revoke blob URLs to prevent memory leaks
- Consider file size limits - Large files might need streaming approaches
This utility provides a solid foundation for file downloads in React apps. Extend it based on your specific requirements!