@umituz/react-native-tanstack 1.2.16 → 1.2.18
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 +144 -3
- package/package.json +4 -4
- package/src/domain/repositories/BaseRepository.ts +280 -0
- package/src/domain/repositories/RepositoryFactory.ts +135 -0
- package/src/domain/utils/ErrorHelpers.ts +154 -0
- package/src/domain/utils/TypeUtilities.ts +153 -0
- package/src/index.ts +57 -0
- package/src/infrastructure/config/PersisterConfig.ts +4 -4
- package/src/infrastructure/monitoring/DevMonitor.ts +274 -0
- package/src/presentation/hooks/usePrefetch.ts +237 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usePrefetch Hook
|
|
3
|
+
* Presentation layer - Query prefetching utilities
|
|
4
|
+
*
|
|
5
|
+
* General-purpose prefetching for any React Native app
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
9
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
10
|
+
import type { QueryKey, QueryFunction } from '@tanstack/react-query';
|
|
11
|
+
|
|
12
|
+
export interface PrefetchOptions<TData> {
|
|
13
|
+
/**
|
|
14
|
+
* Time in ms that the prefetched data should stay fresh
|
|
15
|
+
*/
|
|
16
|
+
staleTime?: number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Time in ms that unused data stays in cache
|
|
20
|
+
*/
|
|
21
|
+
gcTime?: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Hook for prefetching query data
|
|
26
|
+
*
|
|
27
|
+
* Useful for:
|
|
28
|
+
* - Preloading data before navigation
|
|
29
|
+
* - Warming up cache on mount
|
|
30
|
+
* - Background data refresh
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* function UserProfileList({ userIds }: { userIds: string[] }) {
|
|
35
|
+
* const prefetchUser = usePrefetchQuery(['user'], async (id) => fetchUser(id));
|
|
36
|
+
*
|
|
37
|
+
* return (
|
|
38
|
+
* <FlatList
|
|
39
|
+
* data={userIds}
|
|
40
|
+
* onViewableItemsChanged={({ viewableItems }) => {
|
|
41
|
+
* viewableItems.forEach((item) => {
|
|
42
|
+
* prefetchUser(item.key);
|
|
43
|
+
* });
|
|
44
|
+
* }}
|
|
45
|
+
* />
|
|
46
|
+
* );
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export function usePrefetchQuery<
|
|
51
|
+
TQueryFnData = unknown,
|
|
52
|
+
TVariables = string | number,
|
|
53
|
+
>(
|
|
54
|
+
queryKey: QueryKey,
|
|
55
|
+
queryFn: (variables: TVariables) => Promise<TQueryFnData>,
|
|
56
|
+
options: PrefetchOptions<TQueryFnData> = {},
|
|
57
|
+
) {
|
|
58
|
+
const queryClient = useQueryClient();
|
|
59
|
+
const prefetchingRef = new Set<TVariables>();
|
|
60
|
+
|
|
61
|
+
const prefetch = useCallback(
|
|
62
|
+
async (variables: TVariables) => {
|
|
63
|
+
if (prefetchingRef.has(variables)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
prefetchingRef.add(variables);
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await queryClient.prefetchQuery({
|
|
71
|
+
queryKey: [...queryKey, variables],
|
|
72
|
+
queryFn: () => queryFn(variables),
|
|
73
|
+
staleTime: options.staleTime,
|
|
74
|
+
gcTime: options.gcTime,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (__DEV__) {
|
|
78
|
+
// eslint-disable-next-line no-console
|
|
79
|
+
console.log('[TanStack Query] Prefetched:', [...queryKey, variables]);
|
|
80
|
+
}
|
|
81
|
+
} finally {
|
|
82
|
+
prefetchingRef.delete(variables);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[queryClient, queryKey, queryFn, options.staleTime, options.gcTime],
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return prefetch;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Hook for prefetching infinite query data
|
|
93
|
+
*
|
|
94
|
+
* Useful for:
|
|
95
|
+
* - Preloading infinite scroll content
|
|
96
|
+
* - Warming up paginated feeds
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* function FeedScreen() {
|
|
101
|
+
* const prefetchFeed = usePrefetchInfiniteQuery(
|
|
102
|
+
* ['feed'],
|
|
103
|
+
* ({ pageParam }) => fetchFeed({ cursor: pageParam })
|
|
104
|
+
* );
|
|
105
|
+
*
|
|
106
|
+
* useEffect(() => {
|
|
107
|
+
* prefetchFeed();
|
|
108
|
+
* }, []);
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export function usePrefetchInfiniteQuery<
|
|
113
|
+
TQueryFnData = unknown,
|
|
114
|
+
TPageParam = unknown,
|
|
115
|
+
>(
|
|
116
|
+
queryKey: QueryKey,
|
|
117
|
+
queryFn: QueryFunction<TQueryFnData, QueryKey, TPageParam>,
|
|
118
|
+
options: PrefetchOptions<TQueryFnData> = {},
|
|
119
|
+
) {
|
|
120
|
+
const queryClient = useQueryClient();
|
|
121
|
+
const hasPrefetchedRef = useRef(false);
|
|
122
|
+
|
|
123
|
+
const prefetch = useCallback(async () => {
|
|
124
|
+
if (hasPrefetchedRef.current) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
hasPrefetchedRef.current = true;
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
await queryClient.prefetchInfiniteQuery({
|
|
132
|
+
queryKey,
|
|
133
|
+
queryFn,
|
|
134
|
+
staleTime: options.staleTime,
|
|
135
|
+
gcTime: options.gcTime,
|
|
136
|
+
initialPageParam: undefined as unknown as TPageParam,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (__DEV__) {
|
|
140
|
+
// eslint-disable-next-line no-console
|
|
141
|
+
console.log('[TanStack Query] Prefetched infinite:', queryKey);
|
|
142
|
+
}
|
|
143
|
+
} catch {
|
|
144
|
+
hasPrefetchedRef.current = false;
|
|
145
|
+
}
|
|
146
|
+
}, [queryClient, queryKey, queryFn, options.staleTime, options.gcTime]);
|
|
147
|
+
|
|
148
|
+
return prefetch;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Hook for prefetching on mount
|
|
153
|
+
*
|
|
154
|
+
* Convenience hook that prefetches data when component mounts
|
|
155
|
+
*
|
|
156
|
+
* @example
|
|
157
|
+
* ```typescript
|
|
158
|
+
* function UserProfile({ userId }: { userId: string }) {
|
|
159
|
+
* usePrefetchOnMount(
|
|
160
|
+
* ['user', userId],
|
|
161
|
+
* () => fetchUser(userId),
|
|
162
|
+
* { staleTime: TIME_MS.MINUTE }
|
|
163
|
+
* );
|
|
164
|
+
*
|
|
165
|
+
* // Component will prefetch user data on mount
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
export function usePrefetchOnMount<TData = unknown>(
|
|
170
|
+
queryKey: QueryKey,
|
|
171
|
+
queryFn: () => Promise<TData>,
|
|
172
|
+
options: PrefetchOptions<TData> = {},
|
|
173
|
+
) {
|
|
174
|
+
const queryClient = useQueryClient();
|
|
175
|
+
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
queryClient.prefetchQuery({
|
|
178
|
+
queryKey,
|
|
179
|
+
queryFn,
|
|
180
|
+
staleTime: options.staleTime,
|
|
181
|
+
gcTime: options.gcTime,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
if (__DEV__) {
|
|
185
|
+
// eslint-disable-next-line no-console
|
|
186
|
+
console.log('[TanStack Query] Prefetched on mount:', queryKey);
|
|
187
|
+
}
|
|
188
|
+
}, [queryClient, queryKey, queryFn, options.staleTime, options.gcTime]);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Hook for prefetching multiple queries
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* function Dashboard() {
|
|
197
|
+
* const prefetchMultiple = usePrefetchMultiple();
|
|
198
|
+
*
|
|
199
|
+
* useEffect(() => {
|
|
200
|
+
* prefetchMultiple([
|
|
201
|
+
* { queryKey: ['user'], queryFn: fetchUser },
|
|
202
|
+
* { queryKey: ['posts'], queryFn: fetchPosts },
|
|
203
|
+
* { queryKey: ['notifications'], queryFn: fetchNotifications },
|
|
204
|
+
* ]);
|
|
205
|
+
* }, []);
|
|
206
|
+
* }
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export function usePrefetchMultiple<TData = unknown>() {
|
|
210
|
+
const queryClient = useQueryClient();
|
|
211
|
+
|
|
212
|
+
return useCallback(
|
|
213
|
+
async (queries: Array<{
|
|
214
|
+
queryKey: QueryKey;
|
|
215
|
+
queryFn: () => Promise<TData>;
|
|
216
|
+
staleTime?: number;
|
|
217
|
+
gcTime?: number;
|
|
218
|
+
}>) => {
|
|
219
|
+
await Promise.all(
|
|
220
|
+
queries.map(({ queryKey, queryFn, staleTime, gcTime }) =>
|
|
221
|
+
queryClient.prefetchQuery({
|
|
222
|
+
queryKey,
|
|
223
|
+
queryFn,
|
|
224
|
+
staleTime,
|
|
225
|
+
gcTime,
|
|
226
|
+
}),
|
|
227
|
+
),
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
if (__DEV__) {
|
|
231
|
+
// eslint-disable-next-line no-console
|
|
232
|
+
console.log('[TanStack Query] Prefetched multiple:', queries.length);
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
[queryClient],
|
|
236
|
+
);
|
|
237
|
+
}
|