Skip to content

Commit

Permalink
Merge branch 'main' into rob/svelte-5-stable
Browse files Browse the repository at this point in the history
  • Loading branch information
wobsoriano authored Jan 17, 2025
2 parents ec066d4 + f04dd19 commit 5e694c8
Show file tree
Hide file tree
Showing 120 changed files with 2,091 additions and 1,855 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
TAG: ${{ inputs.tag }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4.5.0
uses: codecov/codecov-action@v4.6.0
with:
directory: packages
env:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
if: ${{ always() }}
run: npx nx-cloud stop-all-agents
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4.5.0
uses: codecov/codecov-action@v4.6.0
with:
directory: packages
env:
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
22.4.0
22.12.0
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ If you have been assigned to fix an issue or develop a new feature, please follo
pnpm install
```

- We use [pnpm](https://pnpm.io/) v8 for package management (run in case of pnpm-related issues).
- We use [pnpm](https://pnpm.io/) v9 for package management (run in case of pnpm-related issues).

```bash
corepack enable && corepack prepare
Expand Down
11 changes: 3 additions & 8 deletions docs/framework/angular/guides/invalidations-from-mutations.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ replace: { 'useMutation': 'injectMutation', 'hook': 'function' }
[//]: # 'Example'

```ts
class TodoItemComponent {
mutation = injectMutation(() => ({
mutationFn: postTodo,
}))
}
mutation = injectMutation(() => ({
mutationFn: postTodo,
}))
```

[//]: # 'Example'
Expand All @@ -33,9 +31,6 @@ export class TodosComponent {
onSuccess: () => {
this.queryClient.invalidateQueries({ queryKey: ['todos'] })
this.queryClient.invalidateQueries({ queryKey: ['reminders'] })

// OR use the queryClient that is injected into the component
// this.queryClient.invalidateQueries({ queryKey: ['todos'] })
},
}))
}
Expand Down
2 changes: 2 additions & 0 deletions docs/framework/react/guides/disabling-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ If you are using TypeScript, you can use the `skipToken` to disable a query. Thi
[//]: # 'Example3'

```tsx
import { skipToken, useQuery } from '@tanstack/react-query'

function Todos() {
const [filter, setFilter] = React.useState<string | undefined>()

Expand Down
27 changes: 27 additions & 0 deletions docs/framework/react/guides/migrating-to-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,33 @@ This last change is technically a breaking one, and was made so we don't prematu
+ </HydrationBoundary> // [!code ++]
```

### Query defaults changes

`queryClient.getQueryDefaults` will now merge together all matching registrations instead of returning only the first matching registration.

As a result, calls to `queryClient.setQueryDefaults` should now be ordered with _increasing_ specificity.
That is, registrations should be made from the **most generic key** to the **least generic one**.

For example:

```ts
+ queryClient.setQueryDefaults(['todo'], { // [!code ++]
+ retry: false, // [!code ++]
+ staleTime: 60_000, // [!code ++]
+ }) // [!code ++]
queryClient.setQueryDefaults(['todo', 'detail'], {
+ retry: true, // [!code --]
retryDelay: 1_000,
staleTime: 10_000,
})
- queryClient.setQueryDefaults(['todo'], { // [!code --]
- retry: false, // [!code --]
- staleTime: 60_000, // [!code --]
- }) // [!code --]
```

Note that in this specific example, `retry: true` was added to the `['todo', 'detail']` registration to counteract it now inheriting `retry: false` from the more general registration. The specific changes needed to maintain exact behavior will vary depending on your defaults.

[//]: # 'FrameworkSpecificBreakingChanges'

## New Features 🚀
Expand Down
15 changes: 15 additions & 0 deletions docs/framework/react/guides/query-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,18 @@ queryClient.setQueryData(groupOptions(42).queryKey, newGroups)
[//]: # 'Example1'

For Infinite Queries, a separate [`infiniteQueryOptions`](../reference/infiniteQueryOptions.md) helper is available.

You can still override some options at the component level. A very common and useful pattern is to create per-component [`select`](../guides/render-optimizations.md#select) functions:

[//]: # 'Example2'

```ts
// Type inference still works, so query.data will be the return type of select instead of queryFn

const query = useQuery({
...groupOptions(1),
select: (data) => data.groupName,
})
```

[//]: # 'Example2'
4 changes: 2 additions & 2 deletions docs/framework/react/plugins/broadcastQueryClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ broadcastQueryClient({ queryClient, broadcastChannel })
An object of options:

```tsx
interface broadcastQueryClient {
interface BroadcastQueryClientOptions {
/** The QueryClient to sync */
queryClient: QueryClient
/** This is the unique channel name that will be used
Expand All @@ -56,6 +56,6 @@ The default options are:

```tsx
{
broadcastChannel = 'react-query',
broadcastChannel = 'tanstack-query',
}
```
97 changes: 9 additions & 88 deletions docs/framework/react/react-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,108 +92,29 @@ export function useRefreshOnFocus<T>(refetch: () => Promise<T>) {

In the above code, `refetch` is skipped the first time because `useFocusEffect` calls our callback on mount in addition to screen focus.

## Disable re-renders on out of focus Screens

In some situations, including performance concerns, you may want to stop re-renders when a React Native screen gets out of focus. To achieve this we can use `useFocusEffect` from `@react-navigation/native` together with the `notifyOnChangeProps` query option.

This custom hook provides a `notifyOnChangeProps` option that will return an empty array whenever a screen goes out of focus - effectively stopping any re-renders on that scenario. Whenever the screens gets in focus again, the behavior goes back to normal.

```tsx
import React from 'react'
import { NotifyOnChangeProps } from '@tanstack/query-core'
import { useFocusEffect } from '@react-navigation/native'

export function useFocusNotifyOnChangeProps(
notifyOnChangeProps?: NotifyOnChangeProps,
) {
const focusedRef = React.useRef(true)

useFocusEffect(
React.useCallback(() => {
focusedRef.current = true

return () => {
focusedRef.current = false
}
}, []),
)

return () => {
if (!focusedRef.current) {
return []
}

if (typeof notifyOnChangeProps === 'function') {
return notifyOnChangeProps()
}

return notifyOnChangeProps
}
}
```

In the above code, `useFocusEffect` is used to change the value of a reference that the callback will use as a condition.
## Disable queries on out of focus screens

The argument is wrapped in a reference to also guarantee that the returned callback always keeps the same reference.
If you don’t want certain queries to remain “live” while a screen is out of focus, you can use the subscribed prop on useQuery. This prop lets you control whether a query stays subscribed to updates. Combined with React Navigation’s useIsFocused, it allows you to seamlessly unsubscribe from queries when a screen isn’t in focus:

Example usage:

```tsx
function MyComponent() {
const notifyOnChangeProps = useFocusNotifyOnChangeProps()

const { dataUpdatedAt } = useQuery({
queryKey: ['myKey'],
queryFn: async () => {
const response = await fetch(
'https://api.github.com/repos/tannerlinsley/react-query',
)
return response.json()
},
notifyOnChangeProps,
})

return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
```

## Disable queries on out of focus screens

Enabled can also be set to a callback to support disabling queries on out of focus screens without state and re-rendering on navigation, similar to how notifyOnChangeProps works but in addition it wont trigger refetching when invalidating queries with refetchType active.

```tsx
import React from 'react'
import { useFocusEffect } from '@react-navigation/native'

export function useQueryFocusAware() {
const focusedRef = React.useRef(true)

useFocusEffect(
React.useCallback(() => {
focusedRef.current = true

return () => {
focusedRef.current = false
}
}, []),
)

return () => focusedRef.current
}
```

Example usage:
import { useIsFocused } from '@react-navigation/native'
import { useQuery } from '@tanstack/react-query'
import { Text } from 'react-native'

```tsx
function MyComponent() {
const isFocused = useQueryFocusAware()
const isFocused = useIsFocused()

const { dataUpdatedAt } = useQuery({
queryKey: ['key'],
queryFn: () => fetch(...),
enabled: isFocused,
subscribed: isFocused,
})

return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
```

When subscribed is false, the query unsubscribes from updates and won’t trigger re-renders or fetch new data for that screen. Once it becomes true again (e.g., when the screen regains focus), the query re-subscribes and stays up to date.
2 changes: 1 addition & 1 deletion docs/framework/react/reference/infiniteQueryOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ infiniteQueryOptions({

**Options**

You can generally pass everything to `queryOptions` that you can also pass to [`useInfiniteQuery`](../useInfiniteQuery). Some options will have no effect when then forwarded to a function like `queryClient.prefetchInfiniteQuery`, but TypeScript will still be fine with those excess properties.
You can generally pass everything to `infiniteQueryOptions` that you can also pass to [`useInfiniteQuery`](../useInfiniteQuery). Some options will have no effect when then forwarded to a function like `queryClient.prefetchInfiniteQuery`, but TypeScript will still be fine with those excess properties.

- `queryKey: QueryKey`
- **Required**
Expand Down
7 changes: 6 additions & 1 deletion docs/framework/react/reference/useQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const {
select,
staleTime,
structuralSharing,
subscribed,
throwOnError,
},
queryClient,
Expand Down Expand Up @@ -92,7 +93,7 @@ const {
- `staleTime: number | ((query: Query) => number)`
- Optional
- Defaults to `0`
- The time in milliseconds after data is considered stale. This value only applies to the hook it is defined on.
- The time in milliseconds after which data is considered stale. This value only applies to the hook it is defined on.
- If set to `Infinity`, the data will never be considered stale
- If set to a function, the function will be executed with the query to compute a `staleTime`.
- `gcTime: number | Infinity`
Expand Down Expand Up @@ -161,6 +162,10 @@ const {
- Defaults to `true`
- If set to `false`, structural sharing between query results will be disabled.
- If set to a function, the old and new data values will be passed through this function, which should combine them into resolved data for the query. This way, you can retain references from the old data to improve performance even when that data contains non-serializable values.
- `subscribed: boolean`
- Optional
- Defaults to `true`
- If set to `false`, this instance of `useQuery` will not be subscribed to the cache. This means it won't trigger the `queryFn` on its own, and it won't receive updates if data gets into cache by other means.
- `throwOnError: undefined | boolean | (error: TError, query: Query) => boolean`
- Defaults to the global query config's `throwOnError` value, which is `undefined`
- Set this to `true` if you want errors to be thrown in the render phase and propagate to the nearest error boundary
Expand Down
22 changes: 22 additions & 0 deletions docs/framework/react/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,28 @@ declare module '@tanstack/react-query' {
```

[//]: # 'TypingMeta'
[//]: # 'TypingQueryAndMutationKeys'

## Typing query and mutation keys

### Registering the query and mutation key types

Also similarly to registering a [global error type](#registering-a-global-error), you can also register a global `QueryKey` and `MutationKey` type. This allows you to provide more structure to your keys, that matches your application's hierarchy, and have them be typed across all of the library's surface area. Note that the registered type must extend the `Array` type, so that your keys remain an array.

```ts
import '@tanstack/react-query'

type QueryKey = ['dashboard' | 'marketing', ...ReadonlyArray<unknown>]

declare module '@tanstack/react-query' {
interface Register {
queryKey: QueryKey
mutationKey: QueryKey
}
}
```

[//]: # 'TypingQueryAndMutationKeys'
[//]: # 'TypingQueryOptions'

## Typing Query Options
Expand Down
7 changes: 4 additions & 3 deletions docs/reference/QueryClient.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,8 @@ The `getQueryDefaults` method returns the default options which have been set fo
const defaultOptions = queryClient.getQueryDefaults(['posts'])
```

> Note that if several query defaults match the given query key, the **first** matching one is returned.
> This could lead to unexpected behaviours. See [`setQueryDefaults`](#queryclientsetquerydefaults).
> Note that if several query defaults match the given query key, they will be merged together based on the order of registration.
> See [`setQueryDefaults`](#queryclientsetquerydefaults).
## `queryClient.setQueryDefaults`

Expand All @@ -543,7 +543,8 @@ function Component() {
- `options: QueryOptions`

> As stated in [`getQueryDefaults`](#queryclientgetquerydefaults), the order of registration of query defaults does matter.
> Since the **first** matching defaults are returned by `getQueryDefaults`, the registration should be made in the following order: from the **least generic key** to the **most generic one**. This way, in case of specific key, the first matching one would be the expected one.
> Since the matching defaults are merged by `getQueryDefaults`, the registration should be made in the following order: from the **most generic key** to the **least generic one** .
> This way, more specific defaults will override more generic defaults.
## `queryClient.getMutationDefaults`

Expand Down
2 changes: 1 addition & 1 deletion examples/angular/auto-refetching/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^19.1.0-next.0",
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^19.1.0-next.0",
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
4 changes: 2 additions & 2 deletions examples/angular/devtools-panel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@angular/router": "^19.1.0-next.0",
"@tanstack/angular-query-devtools-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-devtools-experimental": "^5.64.1",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^19.1.0-next.0",
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/pagination/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^19.1.0-next.0",
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/query-options-from-a-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@angular/platform-browser": "^19.1.0-next.0",
"@angular/platform-browser-dynamic": "^19.1.0-next.0",
"@angular/router": "^19.1.0-next.0",
"@tanstack/angular-query-experimental": "^5.62.7",
"@tanstack/angular-query-experimental": "^5.64.1",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.15.0"
Expand Down
Loading

0 comments on commit 5e694c8

Please sign in to comment.