Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/true-cameras-wash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/query-core': minor
---

add query and infiniteQuery methods, deprecate old imperative methods
2 changes: 1 addition & 1 deletion docs/eslint/stable-query-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function App() {
```tsx
async function App() {
const queryClient = new QueryClient()
await queryClient.prefetchQuery(options)
await queryClient.query(options)
}
```

Expand Down
10 changes: 6 additions & 4 deletions docs/framework/angular/guides/paginated-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ export class PaginationExampleComponent {
effect(() => {
// Prefetch the next page!
if (!this.query.isPlaceholderData() && this.query.data()?.hasMore) {
this.#queryClient.prefetchQuery({
queryKey: ['projects', this.page() + 1],
queryFn: () => lastValueFrom(fetchProjects(this.page() + 1)),
})
void this.#queryClient
.query({
queryKey: ['projects', this.page() + 1],
queryFn: () => lastValueFrom(fetchProjects(this.page() + 1)),
})
.catch(noop)
}
})
}
Expand Down
4 changes: 2 additions & 2 deletions docs/framework/angular/guides/query-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ref: docs/framework/react/guides/query-options.md
[//]: # 'Example1'

```ts
import { queryOptions } from '@tanstack/angular-query-experimental'
import { queryOptions, noop } from '@tanstack/angular-query-experimental'

@Injectable({
providedIn: 'root',
Expand Down Expand Up @@ -38,7 +38,7 @@ queries = inject(QueriesService)

postQuery = injectQuery(() => this.queries.post(this.postId()))

queryClient.prefetchQuery(this.queries.post(23))
queryClient.query(this.queries.post(23)).catch(noop)
queryClient.setQueryData(this.queries.post(42).queryKey, newPost)
```

Expand Down
6 changes: 4 additions & 2 deletions docs/framework/angular/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,11 @@ computed(() => {

## Typing Query Options

If you inline query options into `injectQuery`, you'll get automatic type inference. However, you might want to extract the query options into a separate function to share them between `injectQuery` and e.g. `prefetchQuery` or manage them in a service. In that case, you'd lose type inference. To get it back, you can use the `queryOptions` helper:
If you inline query options into `injectQuery`, you'll get automatic type inference. However, you might want to extract the query options into a separate function to share them between `injectQuery` and e.g. `queryClient.query`, or manage them in a service. In that case, you'd lose type inference. To get it back, you can use the `queryOptions` helper:

```ts
import { noop } from '@tanstack/angular-query-experimental'

@Injectable({
providedIn: 'root',
})
Expand Down Expand Up @@ -215,7 +217,7 @@ export class Component {
postQuery = injectQuery(this.optionsSignal)

someMethod() {
this.queryClient.prefetchQuery(this.queries.post(23))
void this.queryClient.query(this.queries.post(23)).catch(noop)
}
}
```
Expand Down
68 changes: 40 additions & 28 deletions docs/framework/react/guides/advanced-ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,12 @@ import {
export async function getStaticProps() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
await queryClient
.query({
queryKey: ['posts'],
queryFn: getPosts,
})
.catch(noop)

return {
props: {
Expand Down Expand Up @@ -172,10 +174,12 @@ import Posts from './posts'
export default async function PostsPage() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
await queryClient
.query({
queryKey: ['posts'],
queryFn: getPosts,
})
.catch(noop)

return (
// Neat! Serialization is now as easy as passing props.
Expand Down Expand Up @@ -237,10 +241,12 @@ import CommentsServerComponent from './comments-server'
export default async function PostsPage() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
await queryClient
.query({
queryKey: ['posts'],
queryFn: getPosts,
})
.catch(noop)

return (
<HydrationBoundary state={dehydrate(queryClient)}>
Expand All @@ -261,10 +267,12 @@ import Comments from './comments'
export default async function CommentsServerComponent() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery({
queryKey: ['posts-comments'],
queryFn: getComments,
})
await queryClient
.query({
queryKey: ['posts-comments'],
queryFn: getComments,
})
.catch(noop)

return (
<HydrationBoundary state={dehydrate(queryClient)}>
Expand Down Expand Up @@ -325,8 +333,8 @@ import Posts from './posts'
export default async function PostsPage() {
const queryClient = new QueryClient()

// Note we are now using fetchQuery()
const posts = await queryClient.fetchQuery({
// Note we are getting the result from query
const posts = await queryClient.query({
queryKey: ['posts'],
queryFn: getPosts,
})
Expand Down Expand Up @@ -355,7 +363,7 @@ Using React Query with Server Components makes most sense if:

It's hard to give general advice on when it makes sense to pair React Query with Server Components and not. **If you are just starting out with a new Server Components app, we suggest you start out with any tools for data fetching your framework provides you with and avoid bringing in React Query until you actually need it.** This might be never, and that's fine, use the right tool for the job!

If you do use it, a good rule of thumb is to avoid `queryClient.fetchQuery` unless you need to catch errors. If you do use it, don't render its result on the server or pass the result to another component, even a Client Component one.
If you do use it, a good rule of thumb is to avoid rendering the result of `queryClient.query` on the server or passing it to another component, even a Client Component one.

From the React Query perspective, treat Server Components as a place to prefetch data, nothing more.

Expand Down Expand Up @@ -424,7 +432,7 @@ export function getQueryClient() {

> Note: This works in NextJs and Server Components because React can serialize Promises over the wire when you pass them down to Client Components.

Then, all we need to do is provide a `HydrationBoundary`, but we don't need to `await` prefetches anymore:
Then, all we need to do is provide a `HydrationBoundary`, but we don't need to `await` these prefetches anymore:

```tsx
// app/posts/page.tsx
Expand All @@ -437,10 +445,12 @@ export default function PostsPage() {
const queryClient = getQueryClient()

// look ma, no await
queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: getPosts,
})
void queryClient
.query({
queryKey: ['posts'],
queryFn: getPosts,
})
.catch(noop)

return (
<HydrationBoundary state={dehydrate(queryClient)}>
Expand Down Expand Up @@ -504,10 +514,12 @@ export default function PostsPage() {
const queryClient = getQueryClient()

// look ma, no await
queryClient.prefetchQuery({
queryKey: ['posts'],
queryFn: () => getPosts().then(serialize), // <-- serialize the data on the server
})
void queryClient
.query({
queryKey: ['posts'],
queryFn: () => getPosts().then(serialize), // <-- serialize the data on the server
})
.catch(noop)

return (
<HydrationBoundary state={dehydrate(queryClient)}>
Expand Down
4 changes: 2 additions & 2 deletions docs/framework/react/guides/initial-query-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ There are many ways to supply initial data for a query to the cache before you n
- Declaratively:
- Provide `initialData` to a query to prepopulate its cache if empty
- Imperatively:
- [Prefetch the data using `queryClient.prefetchQuery`](./prefetching.md)
- [Prefetch the data using `queryClient.query`](./prefetching.md)
- [Manually place the data into the cache using `queryClient.setQueryData`](./prefetching.md)

## Using `initialData` to prepopulate a query
Expand Down Expand Up @@ -84,7 +84,7 @@ By default, `initialData` is treated as totally fresh, as if it were just fetche

This option allows the staleTime to be used for its original purpose, determining how fresh the data needs to be, while also allowing the data to be refetched on mount if the `initialData` is older than the `staleTime`. In the example above, our data needs to be fresh within 1 minute, and we can hint to the query when the initialData was last updated so the query can decide for itself whether the data needs to be refetched again or not.

> If you would rather treat your data as **prefetched data**, we recommend that you use the `prefetchQuery` or `fetchQuery` APIs to populate the cache beforehand, thus letting you configure your `staleTime` independently from your initialData
> If you would rather treat your data as **prefetched data**, we recommend that you use the `query` api to populate the cache beforehand, thus letting you configure your `staleTime` independently from your `initialData`.

### Initial Data Function

Expand Down
43 changes: 33 additions & 10 deletions docs/framework/react/guides/migrating-to-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ useIsMutating({ mutationKey, ...filters }) // [!code ++]
```tsx
queryClient.isFetching(key, filters) // [!code --]
queryClient.isFetching({ queryKey, ...filters }) // [!code ++]
queryClient.ensureQueryData(key, filters) // [!code --]
queryClient.ensureQueryData({ queryKey, ...filters }) // [!code ++]
queryClient.getQueriesData(key, filters) // [!code --]
queryClient.getQueriesData({ queryKey, ...filters }) // [!code ++]
queryClient.setQueriesData(key, updater, filters, options) // [!code --]
Expand All @@ -45,14 +43,6 @@ queryClient.invalidateQueries(key, filters, options) // [!code --]
queryClient.invalidateQueries({ queryKey, ...filters }, options) // [!code ++]
queryClient.refetchQueries(key, filters, options) // [!code --]
queryClient.refetchQueries({ queryKey, ...filters }, options) // [!code ++]
queryClient.fetchQuery(key, fn, options) // [!code --]
queryClient.fetchQuery({ queryKey, queryFn, ...options }) // [!code ++]
queryClient.prefetchQuery(key, fn, options) // [!code --]
queryClient.prefetchQuery({ queryKey, queryFn, ...options }) // [!code ++]
queryClient.fetchInfiniteQuery(key, fn, options) // [!code --]
queryClient.fetchInfiniteQuery({ queryKey, queryFn, ...options }) // [!code ++]
queryClient.prefetchInfiniteQuery(key, fn, options) // [!code --]
queryClient.prefetchInfiniteQuery({ queryKey, queryFn, ...options }) // [!code ++]
```

```tsx
Expand All @@ -62,6 +52,39 @@ queryCache.findAll(key, filters) // [!code --]
queryCache.findAll({ queryKey, ...filters }) // [!code ++]
```

### Imperative QueryClient methods

These methods are deprecated as of Tanstack Query `INSERT_FUTURE_V5_MINOR` and will be removed in v6.

If you are coming from v4 or earlier:

```tsx
queryClient.fetchQuery(key, fn, options) // [!code --]
queryClient.query({ queryKey: key, queryFn: fn, ...options }) // [!code ++]
queryClient.fetchInfiniteQuery(key, fn, options) // [!code --]
queryClient.infiniteQuery({
queryKey: key,
queryFn: fn,
...options,
}) // [!code ++]

queryClient.prefetchQuery(key, fn, options) // [!code --]
queryClient.query({ queryKey: key, queryFn: fn, ...options }).catch(noop) // [!code ++]

queryClient.prefetchInfiniteQuery(key, fn, options) // [!code --]
queryClient
.infiniteQuery({ queryKey: key, queryFn: fn, ...options })
.catch(noop) // [!code ++]

queryClient.ensureQueryData(key, options) // [!code --]
queryClient.query({ queryKey: key, ...options, staleTime: 'static' }) // [!code ++]

queryClient.ensureInfiniteQueryData(key, options) // [!code --]
queryClient.infiniteQuery({ queryKey: key, ...options, staleTime: 'static' }) // [!code ++]
```

If you are updating older v5 code, It will be the same as the above except for keeping the single options object

### `queryClient.getQueryData` now accepts queryKey only as an Argument

`queryClient.getQueryData` argument is changed to accept only a `queryKey`
Expand Down
Loading
Loading