Skip to content

Commit e28ea02

Browse files
authored
Merge branch 'main' into main
2 parents 347c4d4 + f2db185 commit e28ea02

File tree

161 files changed

+6278
-3800
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

161 files changed

+6278
-3800
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,5 @@ jobs:
5656
TAG: ${{ inputs.tag }}
5757
- name: Upload coverage to Codecov
5858
uses: codecov/codecov-action@v4
59-
with:
60-
directory: packages
59+
env:
60+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

.github/workflows/pr.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,5 @@ jobs:
4343
run: npx nx-cloud stop-all-agents
4444
- name: Upload coverage to Codecov
4545
uses: codecov/codecov-action@v4
46-
with:
47-
directory: packages
46+
env:
47+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

codecov.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ coverage:
22
status:
33
project:
44
default:
5-
target: 90%
5+
target: auto
66
threshold: 1%
7+
base: auto
78

89
comment:
910
layout: 'header, reach, diff, flags, components'
11+
behavior: default
12+
require_changes: false
13+
require_base: false
14+
require_head: true
15+
hide_project_coverage: false
1016

1117
component_management:
1218
individual_components:

docs/config.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,9 +849,13 @@
849849
"to": "framework/react/examples/rick-morty"
850850
},
851851
{
852-
"label": "Next.js",
852+
"label": "Next.js Pages",
853853
"to": "framework/react/examples/nextjs"
854854
},
855+
{
856+
"label": "Next.js app with prefetching",
857+
"to": "framework/react/examples/nextjs-app-prefetching"
858+
},
855859
{
856860
"label": "Next.js app with streaming",
857861
"to": "framework/react/examples/nextjs-suspense-streaming"

docs/framework/react/community/community-projects.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ A library for creating typesafe standardized query keys, useful for cache manage
8585

8686
Link: https://github.com/lukemorales/query-key-factory
8787

88+
## Rapini
89+
90+
🥬 OpenAPI to React Query (or SWR) & Axios
91+
92+
Link: https://github.com/rametta/rapini
93+
8894
## React Query Kit
8995

9096
🕊️ A toolkit for ReactQuery that makes ReactQuery hooks reusable and typesafe

docs/framework/react/guides/advanced-ssr.md

Lines changed: 88 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@ The first step of any React Query setup is always to create a `queryClient` and
3030
'use client'
3131

3232
// Since QueryClientProvider relies on useContext under the hood, we have to put 'use client' on top
33-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
33+
import {
34+
isServer,
35+
QueryClient,
36+
QueryClientProvider,
37+
} from '@tanstack/react-query'
3438

3539
function makeQueryClient() {
3640
return new QueryClient({
@@ -47,12 +51,12 @@ function makeQueryClient() {
4751
let browserQueryClient: QueryClient | undefined = undefined
4852

4953
function getQueryClient() {
50-
if (typeof window === 'undefined') {
54+
if (isServer) {
5155
// Server: always make a new query client
5256
return makeQueryClient()
5357
} else {
5458
// Browser: make a new query client if we don't already have one
55-
// This is very important so we don't re-make a new client if React
59+
// This is very important, so we don't re-make a new client if React
5660
// suspends during the initial render. This may not be needed if we
5761
// have a suspense boundary BELOW the creation of the query client
5862
if (!browserQueryClient) browserQueryClient = makeQueryClient()
@@ -354,9 +358,80 @@ The Next.js app router automatically streams any part of the application that is
354358

355359
With the prefetching patterns described above, React Query is perfectly compatible with this form of streaming. As the data for each Suspense boundary resolves, Next.js can render and stream the finished content to the browser. This works even if you are using `useQuery` as outlined above because the suspending actually happens when you `await` the prefetch.
356360

357-
Note that right now, you have to await all prefetches for this to work. This means all prefetches are considered critical content and will block that Suspense boundary.
361+
As of React Query v5.40.0, you don't have to `await` all prefetches for this to work, as `pending` Queries can also be dehydrated and sent to the client. This lets you kick off prefetches as early as possible without letting them block an entire Suspense boundary, and streams the _data_ to the client as the query finishes. This can be useful for example if you want to prefetch some content that is only visible after some user interaction, or say if you want to `await` and render the first page of an infinite query, but start prefetching page 2 without blocking rendering.
362+
363+
To make this work, we have to instruct the `queryClient` to also `dehydrate` pending Queries. We can do this globally, or by passing that option directly to `hydrate`:
364+
365+
```tsx
366+
// app/get-query-client.ts
367+
import { QueryClient, defaultShouldDehydrateQuery } from '@tanstack/react-query'
368+
369+
function makeQueryClient() {
370+
return new QueryClient({
371+
defaultOptions: {
372+
queries: {
373+
staleTime: 60 * 1000,
374+
},
375+
dehydrate: {
376+
// per default, only successful Queries are included,
377+
// this includes pending Queries as well
378+
shouldDehydrateQuery: (query) =>
379+
defaultShouldDehydrateQuery(query) ||
380+
query.state.status === 'pending',
381+
},
382+
},
383+
})
384+
}
385+
```
386+
387+
> Note: This works in NextJs and Server Components because React can serialize Promises over the wire when you pass them down to Client Components.
388+
389+
Then, all we need to do is provide a `HydrationBoundary`, but we don't need to `await` prefetches anymore:
390+
391+
```tsx
392+
// app/posts/page.jsx
393+
import {
394+
dehydrate,
395+
HydrationBoundary,
396+
QueryClient,
397+
} from '@tanstack/react-query'
398+
import { getQueryClient } from './get-query-client'
399+
import Posts from './posts'
400+
401+
// the function doesn't need to be `async` because we don't `await` anything
402+
export default function PostsPage() {
403+
const queryClient = getQueryClient()
358404

359-
As an aside, in the future it might be possible to skip the await for "optional" prefetches that are not critical for this Suspense boundary. This would let you kick off prefetches as early as possible without letting them block an entire Suspense boundary, and streaming the _data_ to the client as the query finishes. This could be useful for example if you want to prefetch some content that is only visible after some user interaction, or say if you want to await and render the first page of an infinite query, but start prefetching page 2 without blocking rendering.
405+
// look ma, no await
406+
queryClient.prefetchQuery({
407+
queryKey: ['posts'],
408+
queryFn: getPosts,
409+
})
410+
411+
return (
412+
<HydrationBoundary state={dehydrate(queryClient)}>
413+
<Posts />
414+
</HydrationBoundary>
415+
)
416+
}
417+
```
418+
419+
On the client, the Promise will be put into the QueryCache for us. That means we can now call `useSuspenseQuery` inside the `Posts` component to "use" that Promise (which was created on the Server):
420+
421+
```tsx
422+
// app/posts/posts.tsx
423+
'use client'
424+
425+
export default function Posts() {
426+
const { data } = useSuspenseQuery({ queryKey: ['posts'], queryFn: getPosts })
427+
428+
// ...
429+
}
430+
```
431+
432+
> Note that you could also `useQuery` instead of `useSuspenseQuery`, and the Promise would still be picked up correctly. However, NextJs won't suspend in that case and the component will render in the `pending` status, which also opts out of server rendering the content.
433+
434+
For more information, check out the [Next.js App with Prefetching Example](../../examples/nextjs-app-prefetching).
360435

361436
## Experimental streaming without prefetching in Next.js
362437

@@ -370,7 +445,11 @@ To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
370445
// app/providers.tsx
371446
'use client'
372447

373-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
448+
import {
449+
isServer,
450+
QueryClient,
451+
QueryClientProvider,
452+
} from '@tanstack/react-query'
374453
import * as React from 'react'
375454
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
376455

@@ -389,13 +468,13 @@ function makeQueryClient() {
389468
let browserQueryClient: QueryClient | undefined = undefined
390469

391470
function getQueryClient() {
392-
if (typeof window === 'undefined') {
471+
if (isServer) {
393472
// Server: always make a new query client
394473
return makeQueryClient()
395474
} else {
396475
// Browser: make a new query client if we don't already have one
397-
// This is very important so we don't re-make a new client if React
398-
// supsends during the initial render. This may not be needed if we
476+
// This is very important, so we don't re-make a new client if React
477+
// suspends during the initial render. This may not be needed if we
399478
// have a suspense boundary BELOW the creation of the query client
400479
if (!browserQueryClient) browserQueryClient = makeQueryClient()
401480
return browserQueryClient

docs/framework/react/guides/optimistic-updates.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,21 @@ This is the simpler variant, as it doesn't interact with the cache directly.
1212
[//]: # 'ExampleUI1'
1313

1414
```tsx
15-
const { isPending, submittedAt, variables, mutate, isError } = useMutation({
15+
const addTodoMutation = useMutation({
1616
mutationFn: (newTodo: string) => axios.post('/api/data', { text: newTodo }),
1717
// make sure to _return_ the Promise from the query invalidation
1818
// so that the mutation stays in `pending` state until the refetch is finished
1919
onSettled: async () => {
2020
return await queryClient.invalidateQueries({ queryKey: ['todos'] })
2121
},
2222
})
23+
24+
const { isPending, submittedAt, variables, mutate, isError } = addTodoMutation
2325
```
2426

2527
[//]: # 'ExampleUI1'
2628

27-
you will then have access to `addTodoMutation.variables`, which contain the added todo. In your UI list, where the query is rendered, you can append another item to the list while the mutation is `pending`:
29+
you will then have access to `addTodoMutation.variables`, which contain the added todo. In your UI list, where the query is rendered, you can append another item to the list while the mutation `isPending`:
2830

2931
[//]: # 'ExampleUI2'
3032

docs/framework/react/guides/prefetching.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,18 @@ This starts fetching `'article-comments'` immediately and flattens the waterfall
199199
If you want to prefetch together with Suspense, you will have to do things a bit differently. You can't use `useSuspenseQueries` to prefetch, since the prefetch would block the component from rendering. You also can not use `useQuery` for the prefetch, because that wouldn't start the prefetch until after suspenseful query had resolved. What you can do is add a small `usePrefetchQuery` function (we might add this to the library itself at a later point):
200200

201201
```tsx
202-
const usePrefetchQuery = (...args) => {
202+
function usePrefetchQuery(options) {
203203
const queryClient = useQueryClient()
204204

205205
// This happens in render, but is safe to do because ensureQueryData
206206
// only fetches if there is no data in the cache for this query. This
207207
// means we know no observers are watching the data so the side effect
208208
// is not observable, which is safe.
209-
queryClient.ensureQueryData(...args)
209+
if (!queryClient.getQueryState(options.queryKey)) {
210+
queryClient.ensureQueryData(options).catch(() => {
211+
// Avoid uncaught error
212+
})
213+
}
210214
}
211215
```
212216

docs/framework/react/guides/suspense.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ To achieve this, wrap your app in the `ReactQueryStreamedHydration` component:
118118
// app/providers.tsx
119119
'use client'
120120

121-
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
121+
import {
122+
isServer,
123+
QueryClient,
124+
QueryClientProvider,
125+
} from '@tanstack/react-query'
122126
import * as React from 'react'
123127
import { ReactQueryStreamedHydration } from '@tanstack/react-query-next-experimental'
124128

@@ -137,13 +141,13 @@ function makeQueryClient() {
137141
let browserQueryClient: QueryClient | undefined = undefined
138142

139143
function getQueryClient() {
140-
if (typeof window === 'undefined') {
144+
if (isServer) {
141145
// Server: always make a new query client
142146
return makeQueryClient()
143147
} else {
144148
// Browser: make a new query client if we don't already have one
145-
// This is very important so we don't re-make a new client if React
146-
// supsends during the initial render. This may not be needed if we
149+
// This is very important, so we don't re-make a new client if React
150+
// suspends during the initial render. This may not be needed if we
147151
// have a suspense boundary BELOW the creation of the query client
148152
if (!browserQueryClient) browserQueryClient = makeQueryClient()
149153
return browserQueryClient

docs/framework/react/react-native.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ title: React Native
55

66
React Query is designed to work out of the box with React Native, with the exception of the devtools, which are only supported with React DOM at this time.
77

8+
There is a 3rd party [Expo](https://docs.expo.dev/) plugin which you can try: https://github.com/expo/dev-plugins/tree/main/packages/react-query
9+
810
There is a 3rd party [Flipper](https://fbflipper.com/docs/getting-started/react-native/) plugin which you can try: https://github.com/bgaleotti/react-query-native-devtools
911

1012
There is a 3rd party [Reactotron](https://github.com/infinitered/reactotron/) plugin which you can try: https://github.com/hsndmr/reactotron-react-query

0 commit comments

Comments
 (0)