Skip to content

Commit

Permalink
Merge branch 'main' into query/core-performance-improvment
Browse files Browse the repository at this point in the history
  • Loading branch information
Aghassi authored Oct 1, 2024
2 parents c1d125c + 71c5f88 commit 5d2e3db
Show file tree
Hide file tree
Showing 117 changed files with 2,035 additions and 294 deletions.
4 changes: 4 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,10 @@
{
"label": "Angular Router",
"to": "framework/angular/examples/router"
},
{
"label": "RxJS autocomplete",
"to": "framework/angular/examples/rxjs"
}
]
}
Expand Down
2 changes: 1 addition & 1 deletion docs/eslint/eslint-plugin-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ Alternatively, add `@tanstack/query` to the plugins section, and configure the r
- [@tanstack/query/exhaustive-deps](../exhaustive-deps)
- [@tanstack/query/no-rest-destructuring](../no-rest-destructuring)
- [@tanstack/query/stable-query-client](../stable-query-client)
- [@tanstack/query/no-unstable-deps](../no-unstable-deps.md)
- [@tanstack/query/no-unstable-deps](../no-unstable-deps)
4 changes: 2 additions & 2 deletions docs/framework/react/guides/mutations.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,15 +226,15 @@ There is a slight difference in handling `onSuccess`, `onError` and `onSettled`
```tsx
useMutation({
mutationFn: addTodo,
onSuccess: (data, error, variables, context) => {
onSuccess: (data, variables, context) => {
// Will be called 3 times
},
})

const todos = ['Todo 1', 'Todo 2', 'Todo 3']
todos.forEach((todo) => {
mutate(todo, {
onSuccess: (data, error, variables, context) => {
onSuccess: (data, variables, context) => {
// Will execute only once, for the last mutation (Todo 3),
// regardless which mutation resolves first
},
Expand Down
2 changes: 1 addition & 1 deletion docs/framework/react/guides/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ Amazing, we've mostly flattened our waterfalls! There's a catch though. Let's ca

This is because with SPA's, server rendering only works for the initial page load, not for any subsequent navigation.

Modern frameworks often tries to solve this by fetching the initial code and data in parallel, so if you were using Next.js or Remix with the prefetching patterns we outlined in this guide, including how to prefetch dependent queries, it would actually look like this instead:
Modern frameworks often try to solve this by fetching the initial code and data in parallel, so if you were using Next.js or Remix with the prefetching patterns we outlined in this guide, including how to prefetch dependent queries, it would actually look like this instead:

```
1. |> JS for <Feed>
Expand Down
50 changes: 50 additions & 0 deletions docs/framework/react/guides/suspense.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ React Query can also be used with React's Suspense for Data Fetching API's. For
- [useSuspenseQuery](../../reference/useSuspenseQuery)
- [useSuspenseInfiniteQuery](../../reference/useSuspenseInfiniteQuery)
- [useSuspenseQueries](../../reference/useSuspenseQueries)
- Additionally, you can use the `useQuery().promise` and `React.use()` (Experimental)

When using suspense mode, `status` states and `error` objects are not needed and are then replaced by usage of the `React.Suspense` component (including the use of the `fallback` prop and React error boundaries for catching errors). Please read the [Resetting Error Boundaries](#resetting-error-boundaries) and look at the [Suspense Example](https://stackblitz.com/github/TanStack/query/tree/main/examples/react/suspense) for more information on how to set up suspense mode.

Expand Down Expand Up @@ -172,3 +173,52 @@ export function Providers(props: { children: React.ReactNode }) {
```

For more information, check out the [NextJs Suspense Streaming Example](../../examples/nextjs-suspense-streaming) and the [Advanced Rendering & Hydration](../advanced-ssr) guide.

## Using `useQuery().promise` and `React.use()` (Experimental)

> To enable this feature, you need to set the `experimental_prefetchInRender` option to `true` when creating your `QueryClient`
**Example code:**

```tsx
const queryClient = new QueryClient({
defaultOptions: {
queries: {
experimental_prefetchInRender: true,
},
},
})
```

**Usage:**

```tsx
import React from 'react'
import { useQuery } from '@tanstack/react-query'
import { fetchTodos, type Todo } from './api'

function TodoList({ query }: { query: UseQueryResult<Todo[]> }) {
const data = React.use(query.promise)

return (
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}

export function App() {
const query = useQuery({ queryKey: ['todos'], queryFn: fetchTodos })

return (
<>
<h1>Todos</h1>
<React.Suspense fallback={<div>Loading...</div>}>
<TodoList query={query} />
</React.Suspense>
</>
)
}
```
2 changes: 1 addition & 1 deletion docs/framework/react/reference/hydration.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const dehydratedState = dehydrate(queryClient, {
- `shouldDehydrateQuery: (query: Query) => boolean`
- Optional
- Whether to dehydrate queries.
- The function, it is called for each query in the cache
- The function is called for each query in the cache
- Return `true` to include this query in dehydration, or `false` otherwise
- Defaults to only including successful queries
- If you would like to extend the function while retaining the default behavior, import and execute `defaultShouldDehydrateQuery` as part of the return statement
Expand Down
5 changes: 5 additions & 0 deletions docs/framework/react/reference/queryOptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,8 @@ You can generally pass everything to `queryOptions` that you can also pass to [`
- `queryKey: QueryKey`
- **Required**
- The query key to generate options for.
- `experimental_prefetchInRender?: boolean`
- Optional
- Defaults to `false`
- When set to `true`, queries will be prefetched during render, which can be useful for certain optimization scenarios
- Needs to be turned on for the experimental `useQuery().promise` functionality
5 changes: 5 additions & 0 deletions docs/framework/react/reference/useInfiniteQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const {
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
promise,
...result
} = useInfiniteQuery({
queryKey,
Expand Down Expand Up @@ -85,5 +86,9 @@ The returned properties for `useInfiniteQuery` are identical to the [`useQuery`
- Is the same as `isFetching && !isPending && !isFetchingNextPage && !isFetchingPreviousPage`
- `isRefetchError: boolean`
- Will be `true` if the query failed while refetching a page.
- `promise: Promise<TData>`
- A stable promise that resolves to the query result.
- This can be used with `React.use()` to fetch data
- Requires the `experimental_prefetchInRender` feature flag to be enabled on the `QueryClient`.

Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default refetch behaviour, resulting in outdated data. Make sure to call these functions only in response to user actions, or add conditions like `hasNextPage && !isFetching`.
2 changes: 1 addition & 1 deletion docs/framework/react/reference/useQueries.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@ The `combine` function will only re-run if:
- the `combine` function itself changed referentially
- any of the query results changed

This means that an inlined `combine` function, as shown above, will run on every render. To avoid this, you can wrap the `combine` function in `useCallback`, or extract it so a stable function reference if it doesn't have any dependencies.
This means that an inlined `combine` function, as shown above, will run on every render. To avoid this, you can wrap the `combine` function in `useCallback`, or extract it to a stable function reference if it doesn't have any dependencies.
4 changes: 4 additions & 0 deletions docs/framework/react/reference/useQuery.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const {
isRefetching,
isStale,
isSuccess,
promise,
refetch,
status,
} = useQuery(
Expand Down Expand Up @@ -244,3 +245,6 @@ const {
- Defaults to `true`
- Per default, a currently running request will be cancelled before a new request is made
- When set to `false`, no refetch will be made if there is already a request running.
- `promise: Promise<TData>`
- A stable promise that will be resolved with the data of the query.
- Requires the `experimental_prefetchInRender` feature flag to be enabled on the `QueryClient`.
4 changes: 2 additions & 2 deletions examples/angular/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^17.3.12",
"@angular/platform-browser": "^17.3.12",
"@angular/platform-browser-dynamic": "^17.3.12",
"@tanstack/angular-query-experimental": "^5.56.2",
"@tanstack/angular-query-experimental": "^5.59.0",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.14.8"
Expand All @@ -23,7 +23,7 @@
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.12",
"@tanstack/angular-query-devtools-experimental": "^5.58.0",
"@tanstack/angular-query-devtools-experimental": "^5.59.0",
"typescript": "5.3.3"
}
}
6 changes: 3 additions & 3 deletions examples/angular/basic/src/app/components/post.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<div>
<a (click)="setPostId.emit(-1)" href="#"> Back </a>
</div>
@if (postQuery.status() === 'pending') {
@if (postQuery.isPending()) {
Loading...
} @else if (postQuery.status() === 'error') {
Error: {{ postQuery.error()?.message }}
} @else if (postQuery.isError()) {
Error: {{ postQuery.error().message }}
}
@if (postQuery.data(); as post) {
<h1>{{ post.title }}</h1>
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/basic/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular Query basic example</title>
<title>TanStack Query Angular basic example</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
Expand Down
4 changes: 2 additions & 2 deletions examples/angular/infinite-query-with-max-pages/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@angular/core": "^17.3.12",
"@angular/platform-browser": "^17.3.12",
"@angular/platform-browser-dynamic": "^17.3.12",
"@tanstack/angular-query-experimental": "^5.56.2",
"@tanstack/angular-query-experimental": "^5.59.0",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.14.8"
Expand All @@ -23,7 +23,7 @@
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.12",
"@tanstack/angular-query-devtools-experimental": "^5.58.0",
"@tanstack/angular-query-devtools-experimental": "^5.59.0",
"typescript": "5.3.3"
}
}
4 changes: 2 additions & 2 deletions examples/angular/router/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"@angular/platform-browser": "^17.3.12",
"@angular/platform-browser-dynamic": "^17.3.12",
"@angular/router": "^17.3.12",
"@tanstack/angular-query-experimental": "^5.56.2",
"@tanstack/angular-query-experimental": "^5.59.0",
"rxjs": "^7.8.1",
"tslib": "^2.6.3",
"zone.js": "^0.14.8"
Expand All @@ -24,7 +24,7 @@
"@angular-devkit/build-angular": "^17.3.8",
"@angular/cli": "^17.3.8",
"@angular/compiler-cli": "^17.3.12",
"@tanstack/angular-query-devtools-experimental": "^5.58.0",
"@tanstack/angular-query-devtools-experimental": "^5.59.0",
"typescript": "5.3.3"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
<div>
<a routerLink="/" href="#">Back</a>
</div>
@if (postQuery.status() === 'pending') {
@if (postQuery.isPending()) {
Loading...
} @else if (postQuery.status() === 'error') {
Error: {{ postQuery.error()?.message }}
} @else if (postQuery.isError()) {
Error: {{ postQuery.error().message }}
}
@if (postQuery.data(); as post) {
<h1>{{ post.title }}</h1>
Expand Down
3 changes: 3 additions & 0 deletions examples/angular/router/src/app/components/post.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import { PostsService } from '../services/posts-service'
export default class PostComponent {
#postsService = inject(PostsService)

// The Angular router will automatically bind postId
// as `withComponentInputBinding` is added to `provideRouter`.
// See https://angular.dev/api/router/withComponentInputBinding
postId = input.required({
transform: numberAttribute,
})
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/router/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Angular Query router example</title>
<title>TanStack Query Angular router example</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
Expand Down
4 changes: 4 additions & 0 deletions examples/angular/rxjs/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "Node.js",
"image": "mcr.microsoft.com/devcontainers/javascript-node:18"
}
6 changes: 6 additions & 0 deletions examples/angular/rxjs/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// @ts-check

/** @type {import('eslint').Linter.Config} */
const config = {}

module.exports = config
6 changes: 6 additions & 0 deletions examples/angular/rxjs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# TanStack Query Angular RxJS Example

To run this example:

- `npm install` or `yarn` or `pnpm i` or `bun i`
- `npm run start` or `yarn start` or `pnpm start` or `bun start`
104 changes: 104 additions & 0 deletions examples/angular/rxjs/angular.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"cli": {
"packageManager": "pnpm",
"analytics": false,
"cache": {
"enabled": false
}
},
"newProjectRoot": "projects",
"projects": {
"basic": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"inlineTemplate": true,
"inlineStyle": true,
"skipTests": true
},
"@schematics/angular:class": {
"skipTests": true
},
"@schematics/angular:directive": {
"skipTests": true
},
"@schematics/angular:guard": {
"skipTests": true
},
"@schematics/angular:interceptor": {
"skipTests": true
},
"@schematics/angular:pipe": {
"skipTests": true
},
"@schematics/angular:resolver": {
"skipTests": true
},
"@schematics/angular:service": {
"skipTests": true
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"options": {
"outputPath": "dist/basic",
"index": "src/index.html",
"browser": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico", "src/mockServiceWorker.js"],
"styles": [],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"buildTarget": "basic:build:production"
},
"development": {
"buildTarget": "basic:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"buildTarget": "basic:build"
}
}
}
}
}
}
Loading

0 comments on commit 5d2e3db

Please sign in to comment.