You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/guides/ssr.md
+163-4Lines changed: 163 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -18,10 +18,19 @@ The exact implementation of these mechanisms may vary from platform to platform,
18
18
- Static Generation (SSG)
19
19
- Server-side Rendering (SSR)
20
20
21
+
> Only Server-side Rendering (SSR) is presently supported by React Server Components in Next.js 13's experimental `app` directory.
22
+
21
23
React Query supports both of these forms of pre-rendering regardless of what platform you may be using
22
24
23
25
### Using `initialData`
24
26
27
+
The setup is minimal and this can be a quick solution for some cases, but there are a **few tradeoffs to consider** when compared to the full approach:
28
+
29
+
- If you are calling `useQuery` in a component deeper down in the tree you need to pass the `initialData` down to that point
30
+
- If you are calling `useQuery` with the same query in multiple locations, you need to pass `initialData` to all of them
31
+
- There is no way to know at what time the query was fetched on the server, so `dataUpdatedAt` and determining if the query needs refetching is based on when the page loaded instead
32
+
33
+
#### With standard `pages` directory
25
34
Together with Next.js's [`getStaticProps`](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) or [`getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering), you can pass the data you fetch in either method to `useQuery`'s' `initialData` option. From React Query's perspective, these integrate in the same way, `getStaticProps` is shown below:
26
35
27
36
```tsx
@@ -41,16 +50,77 @@ function Posts(props) {
41
50
}
42
51
```
43
52
44
-
The setup is minimal and this can be a quick solution for some cases, but there are a **few tradeoffs to consider** when compared to the full approach:
53
+
#### With experimental `app` directory
54
+
Fetch your initial data in a Server Component higher up in the component tree, and pass it to your Client Component as a prop.
45
55
46
-
- If you are calling `useQuery` in a component deeper down in the tree you need to pass the `initialData` down to that point
47
-
- If you are calling `useQuery` with the same query in multiple locations, you need to pass `initialData` to all of them
48
-
- There is no way to know at what time the query was fetched on the server, so `dataUpdatedAt` and determining if the query needs refetching is based on when the page loaded instead
56
+
```tsx
57
+
// app/page.jsx
58
+
exportdefaultasyncfunction RootPage() {
59
+
const initialData =awaitgetPosts()
60
+
61
+
return <Postsposts={initialData} />
62
+
}
63
+
```
64
+
65
+
```tsx
66
+
// app/Posts.jsx
67
+
'use client'
68
+
69
+
import { useQuery } from'@tanstack/react-query'
70
+
71
+
exportfunction Posts(props) {
72
+
const {data} =useQuery({
73
+
queryKey: ['posts'],
74
+
queryFn: getPosts,
75
+
initialData: props.posts,
76
+
})
77
+
78
+
// ...
79
+
}
80
+
```
81
+
82
+
The hooks provided by the `react-query` package need to retrieve a `QueryClient` from their context. Wrap your component tree with `<QueryClientProvider>` and pass it an instance of `QueryClient`.
React Query supports prefetching multiple queries on the server in Next.js and then _dehydrating_ those queries to the queryClient. This means the server can prerender markup that is immediately available on page load and as soon as JS is available, React Query can upgrade or _hydrate_ those queries with the full functionality of the library. This includes refetching those queries on the client if they have become stale since the time they were rendered on the server.
53
121
122
+
#### With standard `pages` directory
123
+
54
124
To support caching queries on the server and set up hydration:
55
125
56
126
- Create a new `QueryClient` instance **inside of your app, and on an instance ref (or in React state). This ensures that data is not shared between different users and requests, while still only creating the QueryClient once per component lifecycle.**
@@ -111,6 +181,95 @@ function Posts() {
111
181
112
182
As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content server renders or not by adding or removing `prefetchQuery` for a specific query.
113
183
184
+
#### With experimental `app` directory
185
+
Wrap the `<QueryClientProvier>` and `<Hydrate>` components inside a Client Component that initializes the `QueryClient` your app will use on the client.
186
+
187
+
-`QueryClient` should be created on an instance ref (or in React State ). **This ensures that data is not shared between different users and requests, while still only creating the QueryClient once per component lifecycle.**
188
+
- The `dehydratedState` prop will contain your prefetched data along with `dataUpdatedAt` which provides the time the data was fetched on the server
Prefetch your data inside a Server Component and provide your previously defined Client Component with the dehydrated state of the server-side `QueryClient`.
210
+
211
+
- Create a new QueryClient instance **for each page request. This ensures that data is not shared between users and requests.**
212
+
- Prefetch the data using the clients prefetchQuery method and wait for it to complete
213
+
- Use dehydrate to dehydrate the query cache and pass it to your wrapped client provider via the dehydratedState prop
214
+
- Wrap your component tree with this new Server Component provider
// if using TypeScript, disable typechecking for Server Component returning Promise type
243
+
// @ts-expect-error Server Component
244
+
<Provider>{children}</Provider>
245
+
}
246
+
</body>
247
+
</html>
248
+
)
249
+
}
250
+
```
251
+
252
+
Prefetched data will now be available to components calling `useQuery`. It's fine to prefetch some queries on the server and let others fetch on the client.
253
+
254
+
```tsx
255
+
// app/posts.jsx
256
+
'use client'
257
+
258
+
import { useQuery } from'@tanstack/react-query'
259
+
260
+
function Posts() {
261
+
// This useQuery could just as well happen in some deeper child to
262
+
// the "Posts"-page, data will be available immediately either way
263
+
const { data } =useQuery({ queryKey: ['posts'], queryFn: getPosts })
264
+
265
+
// This query was not prefetched on the server and will not start
266
+
// fetching until on the client, both patterns are fine to mix
There's a catch if you're using [Next.js' rewrites feature](https://nextjs.org/docs/api-reference/next.config.js/rewrites) together with [Automatic Static Optimization](https://nextjs.org/docs/advanced-features/automatic-static-optimization) or `getStaticProps`: It will cause a second hydration by React Query. That's because [Next.js needs to ensure that they parse the rewrites](https://nextjs.org/docs/api-reference/next.config.js/rewrites#rewrite-parameters) on the client and collect any params after hydration so that they can be provided in `router.query`.
0 commit comments