Offline Data Sync Queue in React
✅ Problem Statement
In web applications, users may lose internet connectivity while performing operations like form submissions or API updates. If not handled gracefully, these actions may fail, leading to data loss or poor user experience.
We need to design an Offline Data Sync Queue in React that:
✅ Key Requirements
✅ Design Overview
Components:
🗺️ Flow Diagram
📂 File Structure
/components
├── NetworkStatusProvider.jsx
├── OfflineQueueManager.js
├── DataForm.jsx
└── QueueDisplay.jsx (optional)
💻 Full React Code
1. 📡 NetworkStatusProvider.jsx
import React, { createContext, useEffect, useState } from 'react';
export const NetworkContext = createContext();
export const NetworkStatusProvider = ({ children }) => {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
const handleOnline = () => setIsOnline(true);
const handleOffline = () => setIsOnline(false);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
return (
<NetworkContext.Provider value={{ isOnline }}>
{children}
</NetworkContext.Provider>
);
};
2. 📦 OfflineQueueManager.js
const QUEUE_KEY = 'offlineQueue';
let queue = JSON.parse(localStorage.getItem(QUEUE_KEY)) || [];
export const addToQueue = (request) => {
queue.push(request);
localStorage.setItem(QUEUE_KEY, JSON.stringify(queue));
};
export const processQueue = async (isOnline, apiCall) => {
if (!isOnline || queue.length === 0) return;
while (queue.length > 0) {
const request = queue.shift();
try {
await apiCall(request);
console.log('Synced:', request);
} catch (error) {
console.error('Failed to sync:', request);
queue.unshift(request);
break;
}
}
localStorage.setItem(QUEUE_KEY, JSON.stringify(queue));
};
export const getQueue = () => queue;
3. 📝 DataForm.jsx
import React, { useContext, useState, useEffect } from 'react';
import { NetworkContext } from './NetworkStatusProvider';
import { addToQueue, processQueue } from './OfflineQueueManager';
const mockApiCall = async (data) => {
return new Promise((resolve) => setTimeout(() => resolve({ success: true }), 1000));
};
const DataForm = () => {
const { isOnline } = useContext(NetworkContext);
const [input, setInput] = useState('');
const [status, setStatus] = useState('');
useEffect(() => {
if (isOnline) {
processQueue(isOnline, mockApiCall);
}
}, [isOnline]);
const handleSubmit = async (e) => {
e.preventDefault();
const requestData = { text: input, timestamp: Date.now() };
if (isOnline) {
try {
await mockApiCall(requestData);
setStatus('Synced Successfully');
} catch (err) {
console.error('API Error, adding to queue.');
addToQueue(requestData);
setStatus('Added to Queue');
}
} else {
addToQueue(requestData);
setStatus('Offline: Added to Queue');
}
setInput('');
};
return (
<div className="p-4 max-w-md mx-auto">
<form onSubmit={handleSubmit} className="space-y-2">
<input
type="text"
className="border border-gray-300 p-2 w-full"
placeholder="Enter data"
value={input}
onChange={(e) => setInput(e.target.value)}
required
/>
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
Submit
</button>
</form>
<p className="mt-2 text-sm text-gray-700">{status}</p>
</div>
);
};
export default DataForm;
4. 📊 QueueDisplay.jsx (Optional)
import React, { useState, useEffect } from 'react';
import { getQueue } from './OfflineQueueManager';
const QueueDisplay = () => {
const [queue, setQueue] = useState(getQueue());
useEffect(() => {
const interval = setInterval(() => setQueue(getQueue()), 1000);
return () => clearInterval(interval);
}, []);
if (queue.length === 0) return null;
return (
<div className="p-4 mt-4 border-t">
<h3 className="font-bold mb-2">Pending Requests:</h3>
<ul className="list-disc list-inside">
{queue.map((item, index) => (
<li key={index}>{item.text}</li>
))}
</ul>
</div>
);
};
export default QueueDisplay;
5. 🖥️ App.jsx
import React from 'react';
import { NetworkStatusProvider } from './components/NetworkStatusProvider';
import DataForm from './components/DataForm';
import QueueDisplay from './components/QueueDisplay';
function App() {
return (
<NetworkStatusProvider>
<div className="p-4">
<h1 className="text-2xl font-bold mb-4 text-center">Offline Data Sync Queue</h1>
<DataForm />
<QueueDisplay />
</div>
</NetworkStatusProvider>
);
}
export default App;
✅ Key Features:
📌 Use Cases for Offline Data Sync Queue
1. 📝 Form Submissions in Unstable Networks
Users filling out forms in areas with poor connectivity (like remote locations or while commuting) can continue submitting data without interruption. The form data will be queued and automatically synced once the network is available.
2. 📦 Field Service or Inventory Apps
In warehouse or on-site service apps where technicians or workers may frequently go offline, actions like stock updates, check-ins, or task completions can be safely queued and synced later.
3. 🛒 E-commerce Cart and Orders
Allow users to add items to the cart or place orders even when the connection is lost. The queued actions will be processed as soon as connectivity is restored, preventing frustration and lost sales.
4. ✏️ Content Management Systems (CMS)
Writers and editors working in unstable environments can save drafts, updates, or comments offline. These changes will automatically sync when they regain connectivity.
5. 🚚 Delivery Tracking Apps
Delivery personnel can log deliveries, upload statuses, or mark failed attempts even in offline zones. The queue ensures that updates sync automatically when back online, improving accuracy and timeliness.
🔄 How Offline Data Sync Works After Closing the App
When a user performs actions while offline, the application queues these API requests and stores them in persistent storage such as localStorage or IndexedDB. Unlike in-memory state, this storage is not cleared when the app or browser is closed.
This ensures that even if the user closes the app, the queued requests are safely retained. When the user reopens the app, the application checks the persistent storage on initialization to see if there are any pending requests. If the device is online, the app automatically begins processing the queued requests and syncing them to the server.
If the device is still offline, the queue remains intact and waits until connectivity is restored. Additionally, the application continues to listen for online events using the browser’s navigator.online API, ensuring that the sync can resume as soon as the network is available. This approach guarantees that no data is lost and that offline actions can reliably sync, even across multiple app sessions.
✅ Final Conclusion
The Offline Data Sync Queue in React provides a reliable and user-friendly way to handle offline scenarios in web applications. By intelligently queuing API requests and processing them when the connection is restored, this design improves data reliability, enhances user trust, and ensures seamless application performance across varying network conditions.
SDE-2 Frontend Developer at Coforge - JavaScript | TypeScript | React.js. | Next.js. | React Native
1moInsightful