useBackgroundSync
Queue requests while offline and automatically sync them when connectivity is restored.
Live Demo
Network
Online
Queue
0 pending
Status
Idle
Synced
0
Message Queue
No messages queued yet
How to test
Open DevTools → Network tab → Select "Offline". Queue some messages, then go back online. Messages will automatically sync when the connection is restored.
Installation
npm install react-resilient-hooksUsage
import { useBackgroundSync } from 'react-resilient-hooks';
function MyComponent() {
const { status, enqueue, flush, abortFlush, getQueueSize } = useBackgroundSync({
onSuccess: (req) => console.log('Synced:', req.id),
onError: (req, error) => console.error('Failed:', req.id, error),
onRetry: (req, attempt) => console.log(`Retry #${attempt}`, req.url),
retry: {
maxRetries: 5,
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
},
concurrency: 3,
maxQueueSize: 100,
onQueueFull: 'drop-oldest',
});
const handleSubmit = async (data) => {
try {
await fetch('/api/submit', { method: 'POST', body: JSON.stringify(data) });
} catch {
// Queue for later if network fails
await enqueue('/api/submit', {
method: 'POST',
body: JSON.stringify(data),
});
}
};
const isSyncing = status.status === 'loading';
return (
<div>
<p>Status: {status.status}</p>
<button onClick={() => handleSubmit({ message: 'Hello' })}>Submit</button>
<button onClick={flush} disabled={isSyncing}>Flush</button>
{isSyncing && <button onClick={abortFlush}>Abort</button>}
</div>
);
}API
Options
queueStore?QueueStore<QueuedReq>Custom queue store implementation. Defaults to IndexedDBQueueStore for persistence.
onSuccess?(req: QueuedReq) => voidCallback fired when a request is successfully synced.
onError?(req: QueuedReq, error: Error) => voidCallback fired when a request fails after all retries.
onRetry?(req: QueuedReq, attempt: number, error: Error) => voidCallback fired when a request is being retried.
retry?RetryPolicyRetry configuration: maxRetries (default: 3), retryDelay, shouldRetry.
concurrency?numberNumber of concurrent requests during flush (default: 3).
maxQueueSize?numberMaximum number of items in queue (default: unlimited).
onQueueFull?'drop-oldest' | 'reject'Behavior when queue is full (default: drop-oldest).
debug?boolean | ((msg: string, data?: unknown) => void)Enable debug logging or provide custom logger.
Returns
statusResilientResultCurrent sync status: idle, loading, success, or error.
enqueue(url: string, options?: RequestInit, meta?: Record<string, unknown>) => Promise<string>Add a request to the queue. Returns the request ID.
flush() => Promise<FlushResult>Manually trigger sync. Returns succeeded/failed/pending counts.
abortFlush() => voidCancel the current flush operation.
getQueueSize() => Promise<number>Get current number of requests in the queue.
clearQueue() => Promise<void>Clear all queued requests.
Queue Stores
The hook supports different storage backends for the request queue:
- IndexedDBQueueStore (default): Persists across page reloads and browser restarts
- MemoryQueueStore: Fast but volatile - lost on page reload
import { MemoryQueueStore } from 'react-resilient-hooks';
const { enqueue } = useBackgroundSync({
queueStore: new MemoryQueueStore(),
});Flush Result
const result = await flush();
// {
// succeeded: 5, // Successfully synced
// failed: 1, // Failed after all retries
// pending: 2, // Still in queue (added during flush)
// errors: [{ req, error, statusCode, attempts }]
// }How It Works
- When you call
enqueue(), the request is stored in IndexedDB - When connectivity is restored, queued requests are automatically flushed
- Requests are processed in parallel (configurable concurrency)
- Failed requests are retried with exponential backoff
- After max retries, failed requests are reported in the flush result
- You can abort a flush in progress with
abortFlush()
This ensures no data is lost even when the user goes offline unexpectedly.