react-storage-drafts
react-storage-drafts is a lightweight, flexible React context provider for managing, storing, and syncing local drafts (e.g. offline forms, notes, cached edits) with optional syncing strategies like intervals, connection changes, or manual triggers.
🚀 Features
- Store drafts locally in memory
- Add, update, and remove drafts
- Sync unsynced drafts with external storage
- Configurable sync triggers:
onChange
,interval
,connection
, ormanual
- Optional integration with online/offline detection (via
navigator.onLine
or React NativeNetInfo
)
📦 Installation
npm install react-storage-drafts
or
yarn add react-storage-drafts
🔧 Usage
1. Wrap your app with the Provider
import { Provider } from 'react-storage-drafts';
<Provider
referenceKey="id"
syncTrigger="connection" // or 'onChange' | 'interval' | 'manual'
syncInterval={60} // optional, in seconds
onSync={async (drafts) => {
// Sync changed drafts to external storage (e.g. API)
// Drafts will have a status property: 'changed' | 'removed'
await api.saveDrafts(drafts);
}}
onLoadStoredData={async () => {
return await api.loadDrafts();
}}
>
<YourApp />
</Provider>
2. Access drafts with useDrafts hook
import { useDrafts } from 'react-storage-drafts';
const { drafts, count, addDraft, updateDraft, removeDraft, clearDrafts } = useDrafts();
// Example:
addDraft({ id: 'draft-1', title: 'New Draft' });
🧠 API Reference
<Provider />
Prop | Type | Required | Description | |||
---|---|---|---|---|---|---|
referenceKey |
string |
❌ | Key used to identify and manage each draft. If not provided, _duid autogenerated property will be used. |
|||
syncTrigger |
`'onChange' \ | 'interval' \ | 'connection' \ | 'manual'` | ✅ | Determines when to trigger syncing. |
syncInterval |
number |
❌ | Sync interval (in seconds) if syncTrigger is 'interval' . Defaults to 120 . |
|||
onSync |
`(drafts: any[]) => void \ | Promise<void>` | ✅ | Callback to sync unsynced drafts to external storage. Unsyced drafts will have changed (new/modified) or removed status |
||
onLoadStoredData |
() => Promise<any[]> |
❌ | Callback to load initial data into the context. |
useDrafts Hook
Use useDrafts()
to access these values:
{
drafts: any[];
count: number;
addDraft: (draft: any) => void;
updateDraft: (key: string | number, changes: any) => void;
removeDraft: (key: string | number) => void;
clearDrafts: () => void;
handleSync: () => void; // Manually trigger sync (if set 'manual' syncTrigger in provider)
}
useDraft Hook
Use useDraft({ draftId: '' })
to manage a single draft:
draftId
is the key of the draft you want to manage. Setting draftId
to first
or last
will return the first or last draft in the list, respectively.
{
draft: any;
update: (changes: any) => void;
remove: () => void;
}
🧪 Sync Triggers
onChange
: Syncs immediately after adding/updating/removing a draft.interval
: Syncs everysyncInterval
seconds.connection
: Syncs automatically when the app goes online.manual
: You can call the exposedsyncData
manually (exposing this is coming soon).
🌐 Online Detection
When using syncTrigger="connection"
, the provider uses the useOnline
hook to detect if the app is online.
Web: uses
navigator.onLine
andonline/offline
eventsReact Native: uses
@react-native-community/netinfo
📁 File Structure
src/
├── Provider.tsx # The main context provider
├── Context.ts # React Context object
├── useOnline.ts # Hook for online status
├── useDrafts.ts # Hook for drafts management
├── types.ts # Type declarations
📝 License
MIT © BossBele
💬 Contributing / Issues
PRs and issues are welcome! Open an issue on the GitHub repo.
🛠️ TODOs
- [x] Expose manual sync method
- [ ] Add persistent storage with localStorage/AsyncStorage
- [ ] Bundle as ESM + CJS for wider compatibility