@umituz/react-native-design-system 2.8.9 → 2.8.11

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 (26) hide show
  1. package/package.json +8 -1
  2. package/src/exports/tanstack.ts +1 -0
  3. package/src/index.ts +5 -0
  4. package/src/media/presentation/hooks/useCardMediaUpload.ts +1 -1
  5. package/src/media/presentation/hooks/useCardMultimediaFlashcard.ts +3 -3
  6. package/src/media/presentation/hooks/useMediaUpload.ts +1 -1
  7. package/src/media/presentation/hooks/useMultimediaFlashcard.ts +3 -3
  8. package/src/tanstack/domain/constants/CacheDefaults.ts +63 -0
  9. package/src/tanstack/domain/repositories/BaseRepository.ts +280 -0
  10. package/src/tanstack/domain/repositories/RepositoryFactory.ts +135 -0
  11. package/src/tanstack/domain/types/CacheStrategy.ts +115 -0
  12. package/src/tanstack/domain/utils/ErrorHelpers.ts +154 -0
  13. package/src/tanstack/domain/utils/QueryKeyFactory.ts +134 -0
  14. package/src/tanstack/domain/utils/TypeUtilities.ts +153 -0
  15. package/src/tanstack/index.ts +161 -0
  16. package/src/tanstack/infrastructure/config/PersisterConfig.ts +162 -0
  17. package/src/tanstack/infrastructure/config/QueryClientConfig.ts +154 -0
  18. package/src/tanstack/infrastructure/config/QueryClientSingleton.ts +69 -0
  19. package/src/tanstack/infrastructure/monitoring/DevMonitor.ts +274 -0
  20. package/src/tanstack/infrastructure/providers/TanstackProvider.tsx +105 -0
  21. package/src/tanstack/presentation/hooks/useInvalidateQueries.ts +128 -0
  22. package/src/tanstack/presentation/hooks/useOptimisticUpdate.ts +88 -0
  23. package/src/tanstack/presentation/hooks/usePaginatedQuery.ts +129 -0
  24. package/src/tanstack/presentation/hooks/usePrefetch.ts +237 -0
  25. package/src/tanstack/presentation/utils/RetryHelpers.ts +67 -0
  26. package/src/tanstack/types/global.d.ts +1 -0
@@ -0,0 +1,105 @@
1
+ import React from 'react';
2
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
3
+ import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
4
+ import type { Persister } from '@tanstack/react-query-persist-client';
5
+ import { createQueryClient, type QueryClientFactoryOptions } from '../config/QueryClientConfig';
6
+ import { createPersister, type PersisterFactoryOptions } from '../config/PersisterConfig';
7
+ import { setGlobalQueryClient } from '../config/QueryClientSingleton';
8
+
9
+ /**
10
+ * TanStack provider props
11
+ */
12
+ export interface TanstackProviderProps {
13
+ /**
14
+ * Child components
15
+ */
16
+ children: React.ReactNode;
17
+
18
+ /**
19
+ * Custom QueryClient instance
20
+ * If not provided, a default one will be created
21
+ */
22
+ queryClient?: QueryClient;
23
+
24
+ /**
25
+ * QueryClient configuration options
26
+ * Only used if queryClient is not provided
27
+ */
28
+ queryClientOptions?: QueryClientFactoryOptions;
29
+
30
+ /**
31
+ * Enable AsyncStorage persistence
32
+ * @default true
33
+ */
34
+ enablePersistence?: boolean;
35
+
36
+ /**
37
+ * Custom persister instance
38
+ * Only used if enablePersistence is true
39
+ */
40
+ persister?: Persister;
41
+
42
+ /**
43
+ * Persister configuration options
44
+ * Only used if enablePersistence is true and persister is not provided
45
+ */
46
+ persisterOptions?: PersisterFactoryOptions;
47
+
48
+ /**
49
+ * Callback when persistence is successfully restored
50
+ */
51
+ onPersistSuccess?: () => void;
52
+
53
+ /**
54
+ * Callback when persistence restoration fails
55
+ */
56
+ onPersistError?: () => void;
57
+ }
58
+
59
+ /**
60
+ * TanStack Query provider with optional AsyncStorage persistence
61
+ */
62
+ export function TanstackProvider({
63
+ children,
64
+ queryClient: providedQueryClient,
65
+ queryClientOptions,
66
+ enablePersistence = true,
67
+ persister: providedPersister,
68
+ persisterOptions,
69
+ onPersistSuccess,
70
+ onPersistError,
71
+ }: TanstackProviderProps): React.ReactElement {
72
+ // Create QueryClient if not provided and set as global singleton
73
+ const [queryClient] = React.useState(() => {
74
+ const client = providedQueryClient ?? createQueryClient(queryClientOptions);
75
+ setGlobalQueryClient(client);
76
+ return client;
77
+ });
78
+
79
+ // Create persister if persistence is enabled
80
+ const [persister] = React.useState(() => {
81
+ if (!enablePersistence) return undefined;
82
+ return providedPersister ?? createPersister(persisterOptions);
83
+ });
84
+
85
+ // Without persistence
86
+ if (!enablePersistence || !persister) {
87
+ return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
88
+ }
89
+
90
+ // With persistence
91
+ return (
92
+ <PersistQueryClientProvider
93
+ client={queryClient}
94
+ persistOptions={{
95
+ persister,
96
+ maxAge: persisterOptions?.maxAge,
97
+ buster: persisterOptions?.busterVersion,
98
+ }}
99
+ onSuccess={onPersistSuccess}
100
+ onError={onPersistError}
101
+ >
102
+ {children}
103
+ </PersistQueryClientProvider>
104
+ );
105
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * useInvalidateQueries Hook
3
+ * Presentation layer - Cache invalidation helper
4
+ *
5
+ * General-purpose cache invalidation for any React Native app
6
+ */
7
+
8
+ import { useQueryClient } from '@tanstack/react-query';
9
+ import { useCallback } from 'react';
10
+
11
+ /**
12
+ * Hook for easy cache invalidation
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const invalidate = useInvalidateQueries();
17
+ *
18
+ * // Invalidate all posts queries
19
+ * await invalidate(['posts']);
20
+ *
21
+ * // Invalidate specific post
22
+ * await invalidate(['posts', 'detail', 123]);
23
+ *
24
+ * // Invalidate with predicate
25
+ * await invalidate({
26
+ * predicate: (query) => query.queryKey[0] === 'posts'
27
+ * });
28
+ * ```
29
+ */
30
+ export function useInvalidateQueries() {
31
+ const queryClient = useQueryClient();
32
+
33
+ return useCallback(
34
+ async (queryKey: readonly unknown[]) => {
35
+ await queryClient.invalidateQueries({ queryKey });
36
+
37
+ if (__DEV__) {
38
+
39
+ console.log('[TanStack Query] Invalidated queries:', queryKey);
40
+ }
41
+ },
42
+ [queryClient],
43
+ );
44
+ }
45
+
46
+ /**
47
+ * Hook for invalidating multiple query patterns at once
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const invalidateMultiple = useInvalidateMultipleQueries();
52
+ *
53
+ * // Invalidate posts and comments
54
+ * await invalidateMultiple([['posts'], ['comments']]);
55
+ * ```
56
+ */
57
+ export function useInvalidateMultipleQueries() {
58
+ const queryClient = useQueryClient();
59
+
60
+ return useCallback(
61
+ async (queryKeys: Array<readonly unknown[]>) => {
62
+ await Promise.all(
63
+ queryKeys.map((key) => queryClient.invalidateQueries({ queryKey: key })),
64
+ );
65
+
66
+ if (__DEV__) {
67
+
68
+ console.log('[TanStack Query] Invalidated multiple queries:', queryKeys);
69
+ }
70
+ },
71
+ [queryClient],
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Hook for removing queries from cache
77
+ * More aggressive than invalidation - completely removes the data
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * const removeQueries = useRemoveQueries();
82
+ *
83
+ * // Remove all posts queries
84
+ * await removeQueries(['posts']);
85
+ * ```
86
+ */
87
+ export function useRemoveQueries() {
88
+ const queryClient = useQueryClient();
89
+
90
+ return useCallback(
91
+ async (queryKey: readonly unknown[]) => {
92
+ queryClient.removeQueries({ queryKey });
93
+
94
+ if (__DEV__) {
95
+
96
+ console.log('[TanStack Query] Removed queries:', queryKey);
97
+ }
98
+ },
99
+ [queryClient],
100
+ );
101
+ }
102
+
103
+ /**
104
+ * Hook for resetting queries to their initial state
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * const resetQueries = useResetQueries();
109
+ *
110
+ * // Reset all posts queries
111
+ * await resetQueries(['posts']);
112
+ * ```
113
+ */
114
+ export function useResetQueries() {
115
+ const queryClient = useQueryClient();
116
+
117
+ return useCallback(
118
+ async (queryKey: readonly unknown[]) => {
119
+ await queryClient.resetQueries({ queryKey });
120
+
121
+ if (__DEV__) {
122
+
123
+ console.log('[TanStack Query] Reset queries:', queryKey);
124
+ }
125
+ },
126
+ [queryClient],
127
+ );
128
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * useOptimisticUpdate Hook
3
+ * Presentation layer - Optimistic update helper
4
+ */
5
+
6
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
7
+
8
+ /**
9
+ * Optimistic update configuration
10
+ */
11
+ export interface OptimisticUpdateConfig<TData, TVariables, TError = Error> {
12
+ queryKey: readonly unknown[];
13
+ updater: (oldData: TData | undefined, variables: TVariables) => TData;
14
+ invalidateOnSuccess?: boolean;
15
+ mutationFn: (variables: TVariables) => Promise<TData>;
16
+ onError?: (error: TError, variables: TVariables, context: unknown) => void;
17
+ onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: unknown) => void;
18
+ onSuccess?: (data: TData, variables: TVariables, context: unknown) => void;
19
+ }
20
+
21
+ /**
22
+ * Hook for mutations with optimistic updates and automatic rollback
23
+ */
24
+ export function useOptimisticUpdate<TData = unknown, TVariables = unknown, TError = Error>(
25
+ config: OptimisticUpdateConfig<TData, TVariables, TError>,
26
+ ) {
27
+ const queryClient = useQueryClient();
28
+ const { queryKey, updater, invalidateOnSuccess = true, onError, onSettled, onSuccess, mutationFn } = config;
29
+
30
+ return useMutation({
31
+ mutationFn,
32
+ onMutate: async (variables: TVariables) => {
33
+ await queryClient.cancelQueries({ queryKey });
34
+ const previousData = queryClient.getQueryData<TData>(queryKey);
35
+
36
+ if (previousData !== undefined) {
37
+ const optimisticData = updater(previousData, variables);
38
+ queryClient.setQueryData(queryKey, optimisticData);
39
+
40
+ if (__DEV__) {
41
+
42
+ console.log('[TanStack Query] Optimistic update applied:', queryKey);
43
+ }
44
+ }
45
+
46
+ return { previousData };
47
+ },
48
+ onError: (error: TError, variables: TVariables, context: unknown) => {
49
+
50
+ const ctx = context as any;
51
+ if (ctx?.previousData !== undefined) {
52
+ queryClient.setQueryData(queryKey, ctx.previousData);
53
+
54
+ if (__DEV__) {
55
+
56
+ console.error('[TanStack Query] Optimistic update rolled back:', error);
57
+ }
58
+ }
59
+
60
+ if (onError) {
61
+ onError(error, variables, context);
62
+ }
63
+ },
64
+ onSuccess: (data: TData, variables: TVariables, context: unknown) => {
65
+ if (onSuccess) {
66
+ onSuccess(data, variables, context);
67
+ }
68
+ },
69
+ onSettled: (data: TData | undefined, error: TError | null, variables: TVariables, context: unknown) => {
70
+ if (invalidateOnSuccess && !error) {
71
+ queryClient.invalidateQueries({ queryKey });
72
+ }
73
+
74
+ if (onSettled) {
75
+ onSettled(data, error, variables, context);
76
+ }
77
+ },
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Hook for list mutations with optimistic updates
83
+ */
84
+ export function useOptimisticListUpdate<TData extends unknown[], TVariables = unknown>(
85
+ config: OptimisticUpdateConfig<TData, TVariables, Error>,
86
+ ) {
87
+ return useOptimisticUpdate<TData, TVariables, Error>(config);
88
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * usePaginatedQuery Hook
3
+ * Presentation layer - Pagination helper
4
+ */
5
+
6
+ import { useInfiniteQuery } from '@tanstack/react-query';
7
+ import { useMemo } from 'react';
8
+
9
+ /**
10
+ * Page parameter for cursor-based pagination
11
+ */
12
+ export interface CursorPageParam {
13
+ cursor?: string;
14
+ limit?: number;
15
+ }
16
+
17
+ /**
18
+ * Page parameter for offset-based pagination
19
+ */
20
+ export interface OffsetPageParam {
21
+ offset: number;
22
+ limit: number;
23
+ }
24
+
25
+ /**
26
+ * Paginated response with cursor
27
+ */
28
+ export interface CursorPaginatedResponse<TData> {
29
+ items: TData[];
30
+ nextCursor?: string;
31
+ hasMore: boolean;
32
+ }
33
+
34
+ /**
35
+ * Paginated response with offset
36
+ */
37
+ export interface OffsetPaginatedResponse<TData> {
38
+ items: TData[];
39
+ total: number;
40
+ offset: number;
41
+ limit: number;
42
+ }
43
+
44
+ /**
45
+ * Cursor pagination options
46
+ */
47
+ export interface CursorPaginationOptions<TData> {
48
+ queryKey: readonly unknown[];
49
+ queryFn: (context: { pageParam?: string }) => Promise<CursorPaginatedResponse<TData>>;
50
+ limit?: number;
51
+ enabled?: boolean;
52
+ staleTime?: number;
53
+ gcTime?: number;
54
+ refetchOnMount?: boolean | 'always';
55
+ refetchOnWindowFocus?: boolean | 'always';
56
+ }
57
+
58
+ /**
59
+ * Hook for cursor-based infinite scroll
60
+ */
61
+ export function useCursorPagination<TData>(options: CursorPaginationOptions<TData>) {
62
+ const { queryKey, queryFn, ...restOptions } = options;
63
+
64
+ const result = useInfiniteQuery({
65
+ queryKey,
66
+ queryFn: ({ pageParam }) => queryFn({ pageParam }),
67
+ initialPageParam: undefined as string | undefined,
68
+ getNextPageParam: (lastPage: CursorPaginatedResponse<TData>) =>
69
+ lastPage.hasMore ? lastPage.nextCursor : undefined,
70
+ ...restOptions,
71
+ });
72
+
73
+ const flatData = useMemo(() => {
74
+ if (!result.data?.pages) return [];
75
+ return result.data.pages.flatMap((page) => page.items);
76
+ }, [result.data]);
77
+
78
+ return {
79
+ ...result,
80
+ flatData,
81
+ totalItems: flatData.length,
82
+ };
83
+ }
84
+
85
+ /**
86
+ * Offset pagination options
87
+ */
88
+ export interface OffsetPaginationOptions<TData> {
89
+ queryKey: readonly unknown[];
90
+ queryFn: (context: { pageParam: OffsetPageParam }) => Promise<OffsetPaginatedResponse<TData>>;
91
+ limit?: number;
92
+ enabled?: boolean;
93
+ staleTime?: number;
94
+ gcTime?: number;
95
+ refetchOnMount?: boolean | 'always';
96
+ refetchOnWindowFocus?: boolean | 'always';
97
+ }
98
+
99
+ /**
100
+ * Hook for offset-based pagination
101
+ */
102
+ export function useOffsetPagination<TData>(options: OffsetPaginationOptions<TData>) {
103
+ const { queryKey, queryFn, limit = 20, ...restOptions } = options;
104
+
105
+ const result = useInfiniteQuery({
106
+ queryKey,
107
+ queryFn: ({ pageParam }) => queryFn({ pageParam }),
108
+ initialPageParam: { offset: 0, limit },
109
+ getNextPageParam: (lastPage: OffsetPaginatedResponse<TData>) => {
110
+ const nextOffset = lastPage.offset + lastPage.limit;
111
+ return nextOffset < lastPage.total ? { offset: nextOffset, limit } : undefined;
112
+ },
113
+ ...restOptions,
114
+ });
115
+
116
+ const flatData = useMemo(() => {
117
+ if (!result.data?.pages) return [];
118
+ return result.data.pages.flatMap((page) => page.items);
119
+ }, [result.data]);
120
+
121
+ const total = result.data?.pages?.[result.data.pages.length - 1]?.total ?? 0;
122
+
123
+ return {
124
+ ...result,
125
+ flatData,
126
+ totalItems: flatData.length,
127
+ total,
128
+ };
129
+ }
@@ -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 {
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 = {},
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
+
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 = {},
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
+
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 = {},
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
+
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
+
232
+ console.log('[TanStack Query] Prefetched multiple:', queries.length);
233
+ }
234
+ },
235
+ [queryClient],
236
+ );
237
+ }