@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.
Files changed (2) hide show
  1. package/README.md +151 -3
  2. 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
  [![npm version](https://img.shields.io/npm/v/@mustafaaksoy41/react-native-offline-queue?style=for-the-badge&logo=npm&logoColor=white&color=CB3837)](https://www.npmjs.com/package/@mustafaaksoy41/react-native-offline-queue)
12
12
  [![npm downloads](https://img.shields.io/npm/dm/@mustafaaksoy41/react-native-offline-queue?style=for-the-badge&logo=npm&logoColor=white&color=CB3837)](https://www.npmjs.com/package/@mustafaaksoy41/react-native-offline-queue)
13
- [![license](https://img.shields.io/npm/l/@mustafaaksoy41/react-native-offline-queue?style=for-the-badge&logo=opensourceinitiative&logoColor=white&color=3DA639)](https://github.com/mustafaaksoy41/react-native-offline-queue/blob/main/LICENSE)
14
- [![bundle size](https://img.shields.io/bundlephobia/minzip/@mustafaaksoy41/react-native-offline-queue?style=for-the-badge&logo=webpack&logoColor=white&color=8DD6F9&label=size)](https://bundlephobia.com/package/@mustafaaksoy41/react-native-offline-queue)
13
+ [![license](https://img.shields.io/npm/l/@mustafaaksoy41/react-native-offline-queue?style=for-the-badge&logo=opensourceinitiative&logoColor=white&color=3DA639)](https://github.com/messivite/react-native-offline-queue/blob/main/LICENSE)
14
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/%40mustafaaksoy41%2Freact-native-offline-queue?style=for-the-badge&logo=webpack&logoColor=white&color=8DD6F9&label=size)](https://bundlephobia.com/package/@mustafaaksoy41/react-native-offline-queue)
15
15
 
16
16
  <!-- Platform & Language -->
17
17
  [![Platform - Android](https://img.shields.io/badge/Android-3DDC84?style=for-the-badge&logo=android&logoColor=white)](https://reactnative.dev/)
18
18
  [![Platform - iOS](https://img.shields.io/badge/iOS-000000?style=for-the-badge&logo=apple&logoColor=white)](https://reactnative.dev/)
19
19
  [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
20
20
  [![React Native](https://img.shields.io/badge/React_Native-61DAFB?style=for-the-badge&logo=react&logoColor=black)](https://reactnative.dev/)
21
+ [![React Query](https://img.shields.io/badge/React_Query-FF4154?style=for-the-badge&logo=tanstackquery&logoColor=white)](https://tanstack.com/query/latest)
21
22
 
22
23
  <!-- Supported Storage Adapters -->
23
24
  [![MMKV](https://img.shields.io/badge/MMKV-FF6C37?style=for-the-badge&logo=firebase&logoColor=white)](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.2",
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": "*",