react-offline-sync-hook
v1.0.7
Published
A comprehensive React hook for offline data synchronization with automatic conflict resolution and queue management
Maintainers
Readme
React Offline Sync Hook 🗄️
The website will work even when the network is offline.
A comprehensive React hook for offline data synchronization with automatic conflict resolution, queue management, and background sync capabilities.
✅ Features
- React Hook →
useOfflineSync(core) - LocalStorage Adapter → Fast, simple storage
- IndexedDB Adapter → Large data storage
- Data Queue Manager → Auto retry with exponential backoff
- Online/Offline Status → Real-time network monitoring
- Auto Sync When Online → Seamless data synchronization
- Conflict Resolution (LWW) → Last-write-wins strategy
- Custom Conflict Handler → User-defined resolution logic
- Manual Sync Trigger → On-demand synchronization
- Background Sync → Service Worker integration
- Batching Requests → Optimized network usage
- Error Logging System → Comprehensive error tracking
- Retry with Exponential Backoff → Smart retry mechanism
- Status API → Real-time sync status
- React Context Provider →
<OfflineSyncProvider> - Hook Return Values → Complete API surface
- TypeScript Support → Full type safety
- JavaScript Support → Compiled builds
- Universal Support → Next.js, CRA, Remix
- Easy API Integration → Ready-to-use
🚀 Live Demo & Documentation
- Coming Soon...
🚀 Installation
npm install react-offline-sync-hook
# or
yarn add react-offline-sync-hook
# or
pnpm add react-offline-sync-hook📖 Quick Start
Basic Usage
import React from "react";
import { OfflineSyncProvider, useOfflineSync } from "react-offline-sync-hook";
// 1. Configure the sync behavior
const config = {
storageAdapter: "indexedDB",
apiEndpoint: "https://your-api.com/api/todos",
retryAttempts: 3,
conflictResolution: "last-write-wins",
enableBackgroundSync: true,
};
// 2. Create your component
const TodoApp = () => {
const { data, addItem, updateItem, deleteItem, status } = useOfflineSync(
"todos",
config
);
return (
<div>
<div>Status: {status.isOnline ? "🟢 Online" : "🔴 Offline"}</div>
<button onClick={() => addItem({ title: "New Todo", completed: false })}>
Add Todo
</button>
{data.map((todo) => (
<div key={todo.id}>
{todo.title}
<button onClick={() => deleteItem(todo.id)}>Delete</button>
</div>
))}
</div>
);
};
// 3. Wrap with Provider
const App = () => (
<OfflineSyncProvider config={config}>
<TodoApp />
</OfflineSyncProvider>
);🔧 Configuration Options
interface SyncConfig {
// Storage
storageAdapter: "localStorage" | "indexedDB";
// API
apiEndpoint: string;
headers?: Record<string, string>;
// Retry Logic
retryAttempts?: number; // Default: 3
retryDelay?: number; // Default: 1000ms
// Batching
batchSize?: number; // Default: 10
// Conflict Resolution
conflictResolution?:
| "client-wins"
| "server-wins"
| "last-write-wins"
| "custom";
customConflictHandler?: (local: any, remote: any) => any;
// Background Sync
enableBackgroundSync?: boolean; // Default: false
syncInterval?: number; // Auto-sync interval in ms
}📚 API Reference
useOfflineSync Hook
const {
data, // T[] - Your synchronized data
status, // SyncStatus - Current sync state
error, // Error | null - Last error
syncNow, // () => Promise<void> - Manual sync
addItem, // (item: Omit<T, 'id'>) => Promise<void>
updateItem, // (id: string, updates: Partial<T>) => Promise<void>
deleteItem, // (id: string) => Promise<void>
clearData, // () => Promise<void>
} = useOfflineSync<T>(key, config, initialData);SyncStatus Object
interface SyncStatus {
isOnline: boolean; // Network connectivity
isSyncing: boolean; // Currently syncing
lastSync: Date | null; // Last successful sync
pendingItems: number; // Items waiting to sync
error: string | null; // Last error message
}🛠 Advanced Usage
Custom Conflict Resolution
const config = {
conflictResolution: "custom",
customConflictHandler: (localData, remoteData) => {
// Your custom merge logic
return {
...localData,
...remoteData,
title: `${localData.title} (merged)`,
updatedAt: new Date().toISOString(),
};
},
};Background Sync with Service Worker
// 1. Enable in config
const config = {
enableBackgroundSync: true,
// ... other options
};
// 2. Create service worker file: public/offline-sync-sw.js
// (The package provides a generator for this)Multiple Data Types
const todosSync = useOfflineSync<Todo>("todos", todosConfig);
const notesSync = useOfflineSync<Note>("notes", notesConfig);
const contactsSync = useOfflineSync<Contact>("contacts", contactsConfig);🔄 Storage Adapters
LocalStorage (Fast, Limited)
- ✅ Fast access
- ✅ Simple setup
- ❌ ~5-10MB limit
- ❌ Synchronous operations
const config = { storageAdapter: "localStorage" };IndexedDB (Large, Async)
- ✅ Large storage capacity
- ✅ Asynchronous operations
- ✅ Complex queries
- ❌ Slightly more complex
const config = { storageAdapter: "indexedDB" };🚦 Network Detection
The hook automatically detects network changes:
const { status } = useOfflineSync("data", config);
// React to network changes
useEffect(() => {
if (status.isOnline) {
console.log("Back online! Auto-syncing...");
} else {
console.log("Gone offline. Queuing changes...");
}
}, [status.isOnline]);🔁 Retry Mechanism
Built-in exponential backoff:
const config = {
retryAttempts: 5, // Try 5 times
retryDelay: 1000, // Start with 1 second
// Delays: 1s, 2s, 4s, 8s, 16s
};📊 Error Handling & Logging
const { error, status } = useOfflineSync("data", config);
// Handle errors
if (error) {
console.error("Sync error:", error.message);
}
// Check sync status
if (status.error) {
console.warn("Last sync failed:", status.error);
}🌐 Framework Compatibility
Next.js
// pages/_app.tsx or app/layout.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
export default function App({ Component, pageProps }) {
return (
<OfflineSyncProvider config={syncConfig}>
<Component {...pageProps} />
</OfflineSyncProvider>
);
}Create React App
// src/index.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
ReactDOM.render(
<OfflineSyncProvider config={syncConfig}>
<App />
</OfflineSyncProvider>,
document.getElementById("root")
);Remix
// app/root.tsx
import { OfflineSyncProvider } from "react-offline-sync-hook";
export default function App() {
return (
<html>
<head />
<body>
<OfflineSyncProvider config={syncConfig}>
<Outlet />
</OfflineSyncProvider>
</body>
</html>
);
}🧪 Testing
npm test # Run tests
npm run test:watch # Watch mode📦 Build & Publish
# Development
npm run dev
# Build
npm run build
# Lint
npm run lint
# Type check
npm run type-check
# Publish
npm publish🤝 Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
MIT © Biren Gohel
🙏 Acknowledgments
- Inspired by modern offline-first applications
- Built for the React ecosystem
- Designed for real-world use cases
Made with ❤️ for the Biren Gohel
