@mustafaaksoy41/react-native-offline-queue 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +151 -3
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -3,21 +3,22 @@
|
|
|
3
3
|
# 📡 react-native-offline-queue
|
|
4
4
|
|
|
5
5
|
**A lightweight, high-performance offline queue and sync manager for React Native.**
|
|
6
|
-
Queue operations when offline, sync automatically or manually when connectivity returns.
|
|
6
|
+
Queue operations when offline, sync automatically or manually when connectivity returns. Works great with React Query (TanStack Query).
|
|
7
7
|
|
|
8
8
|
<br />
|
|
9
9
|
|
|
10
10
|
<!-- Package Info -->
|
|
11
11
|
[](https://www.npmjs.com/package/@mustafaaksoy41/react-native-offline-queue)
|
|
12
12
|
[](https://www.npmjs.com/package/@mustafaaksoy41/react-native-offline-queue)
|
|
13
|
-
[](https://github.com/
|
|
14
|
-
[](https://github.com/messivite/react-native-offline-queue/blob/main/LICENSE)
|
|
14
|
+
[](https://bundlephobia.com/package/@mustafaaksoy41/react-native-offline-queue)
|
|
15
15
|
|
|
16
16
|
<!-- Platform & Language -->
|
|
17
17
|
[](https://reactnative.dev/)
|
|
18
18
|
[](https://reactnative.dev/)
|
|
19
19
|
[](https://www.typescriptlang.org/)
|
|
20
20
|
[](https://reactnative.dev/)
|
|
21
|
+
[](https://tanstack.com/query/latest)
|
|
21
22
|
|
|
22
23
|
<!-- Supported Storage Adapters -->
|
|
23
24
|
[](https://github.com/mrousavy/react-native-mmkv)
|
|
@@ -185,6 +186,46 @@ function LikeButton({ postId }) {
|
|
|
185
186
|
- **Offline**: The action is saved to the queue, and `onOptimisticSuccess` fires so the UI updates instantly.
|
|
186
187
|
- **When connectivity returns**: Queued actions are synced — per-action handler first, then `onSyncAction` as fallback.
|
|
187
188
|
|
|
189
|
+
### How API requests work (real URLs)
|
|
190
|
+
|
|
191
|
+
The `handler` is where you make the **actual API call** — `fetch`, axios, or your API client. When the user presses a button:
|
|
192
|
+
|
|
193
|
+
1. **Online**: `handler(payload)` runs immediately → your `fetch('https://api.myapp.com/...')` fires right away.
|
|
194
|
+
2. **Offline**: `{ actionName, payload }` is stored in the queue. When connectivity returns, the queue flushes and `handler(payload)` runs for each item → your real API requests are sent.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
function CreatePostScreen() {
|
|
198
|
+
const { mutateOffline } = useOfflineMutation('CREATE_POST', {
|
|
199
|
+
handler: async (payload) => {
|
|
200
|
+
// Your real API URL — runs immediately when online, or after queue flushes when offline
|
|
201
|
+
const res = await fetch('https://api.myapp.com/v1/posts', {
|
|
202
|
+
method: 'POST',
|
|
203
|
+
headers: {
|
|
204
|
+
'Content-Type': 'application/json',
|
|
205
|
+
'Authorization': `Bearer ${await getAuthToken()}`,
|
|
206
|
+
},
|
|
207
|
+
body: JSON.stringify(payload),
|
|
208
|
+
});
|
|
209
|
+
if (!res.ok) throw new Error(await res.text());
|
|
210
|
+
},
|
|
211
|
+
onOptimisticSuccess: () => navigation.goBack(),
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return (
|
|
215
|
+
<Button
|
|
216
|
+
title="Submit"
|
|
217
|
+
onPress={() => mutateOffline({ title, body })}
|
|
218
|
+
/>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
| User action | Network | What happens |
|
|
224
|
+
|-------------|---------|--------------|
|
|
225
|
+
| Button press | Online | `handler` runs → `fetch` fires → API receives request |
|
|
226
|
+
| Button press | Offline | Action queued, `onOptimisticSuccess` fires, UI updates |
|
|
227
|
+
| Connectivity restores | — | Queue flushes → each `handler` runs → real API calls sent |
|
|
228
|
+
|
|
188
229
|
### Full Example
|
|
189
230
|
|
|
190
231
|
Here's what a real app looks like with multiple offline-capable actions. Each component owns its own API logic — no central switch-case needed.
|
|
@@ -264,6 +305,113 @@ function MessageBubble({ chatId }) {
|
|
|
264
305
|
|
|
265
306
|
Each `handler` is self-contained: when the user goes offline, actions are queued with their `actionName`. When connectivity returns, the queue flushes and each action runs through its registered handler automatically.
|
|
266
307
|
|
|
308
|
+
### Using with React Query (TanStack Query)
|
|
309
|
+
|
|
310
|
+
If you already use React Query, this package works alongside it. The key: **share the same API function** for both React Query mutations and the offline queue handler.
|
|
311
|
+
|
|
312
|
+
**Pattern 1 — Shared API layer (recommended)**
|
|
313
|
+
|
|
314
|
+
Define your API calls in one place. Use them in the offline queue `handler` and optionally in React Query's `useMutation`:
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
// api/posts.ts
|
|
318
|
+
export async function createPost(payload: { title: string; body: string }) {
|
|
319
|
+
const res = await fetch('https://api.myapp.com/posts', {
|
|
320
|
+
method: 'POST',
|
|
321
|
+
headers: { 'Content-Type': 'application/json' },
|
|
322
|
+
body: JSON.stringify(payload),
|
|
323
|
+
});
|
|
324
|
+
if (!res.ok) throw new Error(await res.text());
|
|
325
|
+
return res.json();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// CreatePostForm.tsx
|
|
329
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
330
|
+
import { useOfflineMutation } from '@mustafaaksoy41/react-native-offline-queue';
|
|
331
|
+
import { createPost } from './api/posts';
|
|
332
|
+
|
|
333
|
+
function CreatePostForm() {
|
|
334
|
+
const queryClient = useQueryClient();
|
|
335
|
+
|
|
336
|
+
const { mutateOffline } = useOfflineMutation('CREATE_POST', {
|
|
337
|
+
handler: async (payload) => {
|
|
338
|
+
await createPost(payload);
|
|
339
|
+
queryClient.invalidateQueries({ queryKey: ['posts'] });
|
|
340
|
+
},
|
|
341
|
+
onOptimisticSuccess: (payload) => {
|
|
342
|
+
// Add to local list immediately (optimistic update)
|
|
343
|
+
queryClient.setQueryData(['posts'], (old: any) =>
|
|
344
|
+
old ? [...old, { ...payload, id: 'temp', pending: true }] : [payload]
|
|
345
|
+
);
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<Button
|
|
351
|
+
title="Post"
|
|
352
|
+
onPress={() => mutateOffline({ title, body })}
|
|
353
|
+
/>
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
**Pattern 2 — Centralized `onSyncAction` with React Query**
|
|
359
|
+
|
|
360
|
+
Handle all actions in one place and use `queryClient` for cache updates:
|
|
361
|
+
|
|
362
|
+
```tsx
|
|
363
|
+
// App.tsx
|
|
364
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
365
|
+
import { OfflineProvider } from '@mustafaaksoy41/react-native-offline-queue';
|
|
366
|
+
import { createPost, likePost } from './api';
|
|
367
|
+
|
|
368
|
+
function AppWithProviders() {
|
|
369
|
+
const queryClient = useQueryClient();
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<OfflineProvider
|
|
373
|
+
config={{
|
|
374
|
+
storageType: 'mmkv',
|
|
375
|
+
syncMode: 'auto',
|
|
376
|
+
onSyncAction: async (action) => {
|
|
377
|
+
switch (action.actionName) {
|
|
378
|
+
case 'CREATE_POST':
|
|
379
|
+
await createPost(action.payload);
|
|
380
|
+
queryClient.invalidateQueries({ queryKey: ['posts'] });
|
|
381
|
+
break;
|
|
382
|
+
case 'LIKE_POST':
|
|
383
|
+
await likePost(action.payload);
|
|
384
|
+
queryClient.invalidateQueries({ queryKey: ['posts'] });
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
}}
|
|
389
|
+
>
|
|
390
|
+
<YourApp />
|
|
391
|
+
</OfflineProvider>
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Wrap with QueryClientProvider
|
|
396
|
+
export default function App() {
|
|
397
|
+
return (
|
|
398
|
+
<QueryClientProvider client={queryClient}>
|
|
399
|
+
<AppWithProviders />
|
|
400
|
+
</QueryClientProvider>
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
**Summary**
|
|
406
|
+
|
|
407
|
+
| What | Use |
|
|
408
|
+
|------|-----|
|
|
409
|
+
| API call (fetch/axios) | Same function in both `mutationFn` and `handler` |
|
|
410
|
+
| Cache invalidation | `queryClient.invalidateQueries()` inside `handler` or `onSyncAction` |
|
|
411
|
+
| Optimistic updates | `onOptimisticSuccess` + `queryClient.setQueryData()` |
|
|
412
|
+
|
|
413
|
+
React Query handles **queries** (reading data). This package handles **mutations when offline** (queue + sync). They work together.
|
|
414
|
+
|
|
267
415
|
## Configuration
|
|
268
416
|
|
|
269
417
|
```tsx
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mustafaaksoy41/react-native-offline-queue",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "A flexible, high-performance offline queue and synchronizer for React Native.",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "A flexible, high-performance offline queue and synchronizer for React Native. Works great with React Query (TanStack Query).",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
|
7
7
|
"types": "lib/typescript/index.d.ts",
|
|
@@ -23,10 +23,20 @@
|
|
|
23
23
|
"offline",
|
|
24
24
|
"queue",
|
|
25
25
|
"sync",
|
|
26
|
-
"hook"
|
|
26
|
+
"hook",
|
|
27
|
+
"react-query",
|
|
28
|
+
"tanstack-query"
|
|
27
29
|
],
|
|
28
30
|
"author": "Mustafa Aksoy",
|
|
29
31
|
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/messivite/react-native-offline-queue.git"
|
|
35
|
+
},
|
|
36
|
+
"homepage": "https://github.com/messivite/react-native-offline-queue#readme",
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/messivite/react-native-offline-queue/issues"
|
|
39
|
+
},
|
|
30
40
|
"peerDependencies": {
|
|
31
41
|
"@react-native-async-storage/async-storage": "*",
|
|
32
42
|
"@react-native-community/netinfo": "*",
|