@umituz/react-native-tanstack 1.2.7 → 1.2.9
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-tanstack",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "TanStack Query configuration and utilities for React Native apps - Pre-configured QueryClient with AsyncStorage persistence",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/index.ts
CHANGED
|
@@ -1,68 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useOptimisticUpdate Hook
|
|
3
3
|
* Presentation layer - Optimistic update helper
|
|
4
|
-
*
|
|
5
|
-
* General-purpose optimistic updates for any React Native app
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
6
|
import { useMutation, useQueryClient, type UseMutationOptions } from '@tanstack/react-query';
|
|
9
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Context type for optimistic updates
|
|
10
|
+
*/
|
|
11
|
+
interface OptimisticContext<TData> {
|
|
12
|
+
previousData: TData | undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
10
15
|
/**
|
|
11
16
|
* Optimistic update configuration
|
|
12
17
|
*/
|
|
13
18
|
export interface OptimisticUpdateConfig<TData, TVariables> {
|
|
14
|
-
/**
|
|
15
|
-
* Query key to update optimistically
|
|
16
|
-
*/
|
|
17
19
|
queryKey: readonly unknown[];
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Function to update the cached data optimistically
|
|
21
|
-
*/
|
|
22
20
|
updater: (oldData: TData | undefined, variables: TVariables) => TData;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Whether to invalidate the query after successful mutation
|
|
26
|
-
* @default true
|
|
27
|
-
*/
|
|
28
21
|
invalidateOnSuccess?: boolean;
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
/**
|
|
32
25
|
* Hook for mutations with optimistic updates and automatic rollback
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* ```typescript
|
|
36
|
-
* const updatePost = useOptimisticUpdate<Post, UpdatePostVariables>({
|
|
37
|
-
* mutationFn: (variables) => api.updatePost(variables.id, variables.data),
|
|
38
|
-
* queryKey: ['posts', postId],
|
|
39
|
-
* updater: (oldPost, variables) => ({
|
|
40
|
-
* ...oldPost,
|
|
41
|
-
* ...variables.data,
|
|
42
|
-
* }),
|
|
43
|
-
* });
|
|
44
|
-
*
|
|
45
|
-
* // Usage
|
|
46
|
-
* updatePost.mutate({ id: 123, data: { title: 'New Title' } });
|
|
47
|
-
* ```
|
|
48
26
|
*/
|
|
49
27
|
export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TError = Error>(
|
|
50
28
|
config: OptimisticUpdateConfig<TData, TVariables> &
|
|
51
|
-
UseMutationOptions<TData, TError, TVariables>,
|
|
29
|
+
Omit<UseMutationOptions<TData, TError, TVariables, OptimisticContext<TData>>, 'onMutate'>,
|
|
52
30
|
) {
|
|
53
31
|
const queryClient = useQueryClient();
|
|
54
32
|
const { queryKey, updater, invalidateOnSuccess = true, onError, onSettled, ...mutationOptions } = config;
|
|
55
33
|
|
|
56
|
-
return useMutation({
|
|
34
|
+
return useMutation<TData, TError, TVariables, OptimisticContext<TData>>({
|
|
57
35
|
...mutationOptions,
|
|
58
36
|
onMutate: async (variables) => {
|
|
59
|
-
// Cancel outgoing refetches to avoid overwriting optimistic update
|
|
60
37
|
await queryClient.cancelQueries({ queryKey });
|
|
61
|
-
|
|
62
|
-
// Snapshot the previous value
|
|
63
38
|
const previousData = queryClient.getQueryData<TData>(queryKey);
|
|
64
39
|
|
|
65
|
-
// Optimistically update to the new value
|
|
66
40
|
if (previousData !== undefined) {
|
|
67
41
|
const optimisticData = updater(previousData, variables);
|
|
68
42
|
queryClient.setQueryData(queryKey, optimisticData);
|
|
@@ -73,11 +47,9 @@ export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TErro
|
|
|
73
47
|
}
|
|
74
48
|
}
|
|
75
49
|
|
|
76
|
-
// Return context with previous data for rollback
|
|
77
50
|
return { previousData };
|
|
78
51
|
},
|
|
79
|
-
onError: (error, variables, context
|
|
80
|
-
// Rollback to previous data on error
|
|
52
|
+
onError: (error, variables, context) => {
|
|
81
53
|
if (context?.previousData !== undefined) {
|
|
82
54
|
queryClient.setQueryData(queryKey, context.previousData);
|
|
83
55
|
|
|
@@ -87,40 +59,28 @@ export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TErro
|
|
|
87
59
|
}
|
|
88
60
|
}
|
|
89
61
|
|
|
90
|
-
// Call user-provided onError
|
|
91
62
|
if (onError) {
|
|
92
|
-
onError(error, variables, context
|
|
63
|
+
onError(error, variables, context);
|
|
93
64
|
}
|
|
94
65
|
},
|
|
95
|
-
onSettled: (data, error, variables, context
|
|
96
|
-
// Invalidate query to refetch with real data
|
|
66
|
+
onSettled: (data, error, variables, context) => {
|
|
97
67
|
if (invalidateOnSuccess && !error) {
|
|
98
68
|
queryClient.invalidateQueries({ queryKey });
|
|
99
69
|
}
|
|
100
70
|
|
|
101
|
-
// Call user-provided onSettled
|
|
102
71
|
if (onSettled) {
|
|
103
|
-
onSettled(data, error, variables, context
|
|
72
|
+
onSettled(data, error, variables, context);
|
|
104
73
|
}
|
|
105
74
|
},
|
|
106
75
|
});
|
|
107
76
|
}
|
|
108
77
|
|
|
109
78
|
/**
|
|
110
|
-
* Hook for list mutations with optimistic updates
|
|
111
|
-
*
|
|
112
|
-
* @example
|
|
113
|
-
* ```typescript
|
|
114
|
-
* const addPost = useOptimisticListUpdate<Post[], { title: string }>({
|
|
115
|
-
* mutationFn: (variables) => api.createPost(variables),
|
|
116
|
-
* queryKey: ['posts'],
|
|
117
|
-
* updater: (oldPosts, newPost) => [...(oldPosts ?? []), newPost],
|
|
118
|
-
* });
|
|
119
|
-
* ```
|
|
79
|
+
* Hook for list mutations with optimistic updates
|
|
120
80
|
*/
|
|
121
81
|
export function useOptimisticListUpdate<TData extends unknown[], TVariables = unknown>(
|
|
122
82
|
config: OptimisticUpdateConfig<TData, TVariables> &
|
|
123
|
-
UseMutationOptions<TData, Error, TVariables>,
|
|
83
|
+
Omit<UseMutationOptions<TData, Error, TVariables, OptimisticContext<TData>>, 'onMutate'>,
|
|
124
84
|
) {
|
|
125
85
|
return useOptimisticUpdate<TData, TVariables>(config);
|
|
126
86
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* usePaginatedQuery Hook
|
|
3
3
|
* Presentation layer - Pagination helper
|
|
4
|
-
*
|
|
5
|
-
* General-purpose pagination for any React Native app
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
6
|
import {
|
|
9
7
|
useInfiniteQuery,
|
|
10
8
|
type UseInfiniteQueryOptions,
|
|
11
|
-
type InfiniteData,
|
|
12
9
|
} from '@tanstack/react-query';
|
|
13
10
|
import { useMemo } from 'react';
|
|
14
11
|
|
|
@@ -49,18 +46,6 @@ export interface OffsetPaginatedResponse<TData> {
|
|
|
49
46
|
|
|
50
47
|
/**
|
|
51
48
|
* Hook for cursor-based infinite scroll
|
|
52
|
-
*
|
|
53
|
-
* @example
|
|
54
|
-
* ```typescript
|
|
55
|
-
* const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useCursorPagination({
|
|
56
|
-
* queryKey: ['posts'],
|
|
57
|
-
* queryFn: ({ pageParam }) => fetchPosts({ cursor: pageParam, limit: 20 }),
|
|
58
|
-
* limit: 20,
|
|
59
|
-
* });
|
|
60
|
-
*
|
|
61
|
-
* // Flatten all pages into single array
|
|
62
|
-
* const allPosts = data.pages.flatMap(page => page.items);
|
|
63
|
-
* ```
|
|
64
49
|
*/
|
|
65
50
|
export function useCursorPagination<TData>(
|
|
66
51
|
options: Omit<
|
|
@@ -68,6 +53,7 @@ export function useCursorPagination<TData>(
|
|
|
68
53
|
CursorPaginatedResponse<TData>,
|
|
69
54
|
Error,
|
|
70
55
|
CursorPaginatedResponse<TData>,
|
|
56
|
+
CursorPaginatedResponse<TData>,
|
|
71
57
|
readonly unknown[],
|
|
72
58
|
string | undefined
|
|
73
59
|
>,
|
|
@@ -76,7 +62,7 @@ export function useCursorPagination<TData>(
|
|
|
76
62
|
limit?: number;
|
|
77
63
|
},
|
|
78
64
|
) {
|
|
79
|
-
const { limit = 20, ...queryOptions } = options;
|
|
65
|
+
const { limit: _limit = 20, ...queryOptions } = options;
|
|
80
66
|
|
|
81
67
|
const result = useInfiniteQuery({
|
|
82
68
|
...queryOptions,
|
|
@@ -85,11 +71,9 @@ export function useCursorPagination<TData>(
|
|
|
85
71
|
lastPage.hasMore ? lastPage.nextCursor : undefined,
|
|
86
72
|
});
|
|
87
73
|
|
|
88
|
-
// Flatten pages into single array for easier consumption
|
|
89
74
|
const flatData = useMemo(() => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
return infiniteData.pages.flatMap((page) => page.items);
|
|
75
|
+
if (!result.data?.pages) return [];
|
|
76
|
+
return result.data.pages.flatMap((page) => page.items);
|
|
93
77
|
}, [result.data]);
|
|
94
78
|
|
|
95
79
|
return {
|
|
@@ -101,15 +85,6 @@ export function useCursorPagination<TData>(
|
|
|
101
85
|
|
|
102
86
|
/**
|
|
103
87
|
* Hook for offset-based pagination
|
|
104
|
-
*
|
|
105
|
-
* @example
|
|
106
|
-
* ```typescript
|
|
107
|
-
* const { data, fetchNextPage, hasNextPage } = useOffsetPagination({
|
|
108
|
-
* queryKey: ['posts'],
|
|
109
|
-
* queryFn: ({ pageParam }) => fetchPosts({ offset: pageParam.offset, limit: pageParam.limit }),
|
|
110
|
-
* limit: 20,
|
|
111
|
-
* });
|
|
112
|
-
* ```
|
|
113
88
|
*/
|
|
114
89
|
export function useOffsetPagination<TData>(
|
|
115
90
|
options: Omit<
|
|
@@ -117,6 +92,7 @@ export function useOffsetPagination<TData>(
|
|
|
117
92
|
OffsetPaginatedResponse<TData>,
|
|
118
93
|
Error,
|
|
119
94
|
OffsetPaginatedResponse<TData>,
|
|
95
|
+
OffsetPaginatedResponse<TData>,
|
|
120
96
|
readonly unknown[],
|
|
121
97
|
OffsetPageParam
|
|
122
98
|
>,
|
|
@@ -136,16 +112,12 @@ export function useOffsetPagination<TData>(
|
|
|
136
112
|
},
|
|
137
113
|
});
|
|
138
114
|
|
|
139
|
-
// Flatten pages into single array
|
|
140
115
|
const flatData = useMemo(() => {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return infiniteData.pages.flatMap((page) => page.items);
|
|
116
|
+
if (!result.data?.pages) return [];
|
|
117
|
+
return result.data.pages.flatMap((page) => page.items);
|
|
144
118
|
}, [result.data]);
|
|
145
119
|
|
|
146
|
-
|
|
147
|
-
const infiniteData = result.data as InfiniteData<OffsetPaginatedResponse<TData>> | undefined;
|
|
148
|
-
const total = infiniteData?.pages?.[infiniteData.pages.length - 1]?.total ?? 0;
|
|
120
|
+
const total = result.data?.pages?.[result.data.pages.length - 1]?.total ?? 0;
|
|
149
121
|
|
|
150
122
|
return {
|
|
151
123
|
...result,
|