|
1 | | -import { QueryClient, dehydrate } from "@tanstack/react-query" |
| 1 | +import { dehydrate } from "@tanstack/react-query" |
| 2 | +import { getServerQueryClient } from "./serverQueryClient" |
2 | 3 | import type { Query } from "@tanstack/react-query" |
3 | 4 |
|
4 | | -const MAX_RETRIES = 3 |
5 | | -const NO_RETRY_CODES = [400, 401, 403, 404, 405, 409, 422] |
6 | | - |
7 | | -type MaybeHasStatus = { |
8 | | - response?: { |
9 | | - status?: number |
10 | | - } |
11 | | -} |
12 | | - |
13 | | -const getPrefetchQueryClient = () => { |
14 | | - return new QueryClient({ |
15 | | - defaultOptions: { |
16 | | - queries: { |
17 | | - /** |
18 | | - * React Query's default retry logic is only active in the browser. |
19 | | - * Here we explicitly configure it to retry MAX_RETRIES times on |
20 | | - * the server, with an exclusion list of statuses that we expect not |
21 | | - * to succeed on retry. |
22 | | - * |
23 | | - * Includes status undefined as we want to retry on network errors |
24 | | - */ |
25 | | - retry: (failureCount, error) => { |
26 | | - const status = (error as MaybeHasStatus)?.response?.status |
27 | | - const isNetworkError = status === undefined || status === 0 |
28 | | - |
29 | | - if (isNetworkError || !NO_RETRY_CODES.includes(status)) { |
30 | | - return failureCount < MAX_RETRIES |
31 | | - } |
32 | | - return false |
33 | | - }, |
34 | | - |
35 | | - /** |
36 | | - * By default, React Query gradually applies a backoff delay, though it is |
37 | | - * preferable that we do not significantly delay initial page renders (or |
38 | | - * indeed pages that are Statically Rendered during the build process) and |
39 | | - * instead allow the request to fail quickly so it can be subsequently |
40 | | - * fetched on the client. |
41 | | - */ |
42 | | - retryDelay: 1000, |
43 | | - }, |
44 | | - }, |
45 | | - }) |
46 | | -} |
47 | | - |
48 | | -/* Utility to avoid repetition in server components |
| 5 | +/** |
| 6 | + * Utility to avoid repetition in server components |
49 | 7 | * Optionally pass the queryClient returned from a previous prefetch |
50 | 8 | * where queries are dependent on previous results |
51 | 9 | */ |
52 | 10 | export const prefetch = async ( |
53 | 11 | queries: (Query | unknown)[], |
54 | 12 |
|
55 | 13 | /** |
56 | | - * The SSR QueryClient is transient - it is created only for prefetch |
57 | | - * while API requests are made to server render the page and discarded |
58 | | - * as the dehydrated state is produced and sent to the client. |
| 14 | + * Unless passed, the SSR QueryClient uses React's cache() for reuse for the duration of the request. |
59 | 15 | * |
60 | | - * Create a new query client if one is not provided. |
| 16 | + * The QueryClient is garbage collected once the dehydrated state is produced and |
| 17 | + * sent to the client and the request is complete. |
61 | 18 | */ |
62 | | - queryClient = getPrefetchQueryClient(), |
| 19 | + queryClient = getServerQueryClient(), |
63 | 20 | ) => { |
64 | 21 | await Promise.all( |
65 | | - queries |
66 | | - .filter(Boolean) |
67 | | - .map((query) => queryClient.prefetchQuery(query as Query)), |
| 22 | + queries.filter(Boolean).map((query) => { |
| 23 | + return queryClient.prefetchQuery(query as Query) |
| 24 | + }), |
68 | 25 | ) |
69 | 26 |
|
70 | | - return { dehydratedState: dehydrate(queryClient), queryClient } |
| 27 | + return { |
| 28 | + dehydratedState: dehydrate(queryClient), |
| 29 | + queryClient, |
| 30 | + } |
71 | 31 | } |
0 commit comments