diff --git a/docs/framework/react/guides/mutations.md b/docs/framework/react/guides/mutations.md index cc8f099d53..200978a842 100644 --- a/docs/framework/react/guides/mutations.md +++ b/docs/framework/react/guides/mutations.md @@ -267,7 +267,7 @@ try { ## Retry -By default TanStack Query will not retry a mutation on error, but it is possible with the `retry` option: +By default, TanStack Query will not retry a mutation on error, but it is possible with the `retry` option: [//]: # 'Example9' @@ -390,6 +390,23 @@ We also have an extensive [offline example](../../examples/offline) that covers [//]: # 'Materials' +## Mutation Scopes + +Per default, all mutations run in parallel - even if you invoke `.mutate()` of the same mutation multiple times. Mutations can be given a `scope` with an `id` to avoid that. All mutations with the same `scope.id` will run in serial, which means when they are triggered, they will start in `isPaused: true` state if there is already a mutation for that scope in progress. They will be put into a queue and will automatically resume once their time in the queue has come. + +[//]: # 'ExampleScopes' + +```tsx +const mutation = useMutation({ + mutationFn: addTodo, + scope: { + id: 'todo', + }, +}) +``` + +[//]: # 'ExampleScopes' + ## Further reading For more information about mutations, have a look at [#12: Mastering Mutations in React Query](../../community/tkdodos-blog#12-mastering-mutations-in-react-query) from diff --git a/docs/framework/react/reference/useMutation.md b/docs/framework/react/reference/useMutation.md index d24298e994..6c4469d4fe 100644 --- a/docs/framework/react/reference/useMutation.md +++ b/docs/framework/react/reference/useMutation.md @@ -23,6 +23,7 @@ const { } = useMutation({ mutationFn, gcTime, + meta, mutationKey, networkMode, onError, @@ -31,8 +32,8 @@ const { onSuccess, retry, retryDelay, + scope, throwOnError, - meta, }) mutate(variables, { @@ -85,6 +86,10 @@ mutate(variables, { - This function receives a `retryAttempt` integer and the actual Error and returns the delay to apply before the next attempt in milliseconds. - A function like `attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000)` applies exponential backoff. - A function like `attempt => attempt * 1000` applies linear backoff. +- `scope: { id: string }` + - Optional + - Defaults to a unique id (so that all mutations run in parallel) + - Mutations with the same scope id will run in serial - `throwOnError: undefined | boolean | (error: TError) => boolean` - Defaults to the global query config's `throwOnError` value, which is `undefined` - Set this to `true` if you want mutation errors to be thrown in the render phase and propagate to the nearest error boundary diff --git a/examples/angular/basic/package.json b/examples/angular/basic/package.json index b8be500407..6447ca1325 100644 --- a/examples/angular/basic/package.json +++ b/examples/angular/basic/package.json @@ -17,7 +17,7 @@ "@angular/platform-browser": "^17.3.3", "@angular/platform-browser-dynamic": "^17.3.3", "@angular/router": "^17.3.3", - "@tanstack/angular-query-experimental": "^5.30.0", + "@tanstack/angular-query-experimental": "^5.31.0", "rxjs": "^7.8.1", "tslib": "^2.6.2", "zone.js": "^0.14.4" @@ -26,7 +26,7 @@ "@angular-devkit/build-angular": "^17.3.3", "@angular/cli": "^17.3.3", "@angular/compiler-cli": "^17.3.3", - "@tanstack/angular-query-devtools-experimental": "^5.30.0", + "@tanstack/angular-query-devtools-experimental": "^5.31.0", "typescript": "5.2.2" } } diff --git a/examples/angular/infinite-query-with-max-pages/package.json b/examples/angular/infinite-query-with-max-pages/package.json index 94246a05bd..43f90b6704 100644 --- a/examples/angular/infinite-query-with-max-pages/package.json +++ b/examples/angular/infinite-query-with-max-pages/package.json @@ -17,7 +17,7 @@ "@angular/platform-browser": "^17.3.3", "@angular/platform-browser-dynamic": "^17.3.3", "@angular/router": "^17.3.3", - "@tanstack/angular-query-experimental": "^5.30.0", + "@tanstack/angular-query-experimental": "^5.31.0", "rxjs": "^7.8.1", "tslib": "^2.6.2", "zone.js": "^0.14.4" @@ -26,7 +26,7 @@ "@angular-devkit/build-angular": "^17.3.3", "@angular/cli": "^17.3.3", "@angular/compiler-cli": "^17.3.3", - "@tanstack/angular-query-devtools-experimental": "^5.30.0", + "@tanstack/angular-query-devtools-experimental": "^5.31.0", "typescript": "5.2.2" } } diff --git a/examples/angular/router/package.json b/examples/angular/router/package.json index 25aa22eb49..fe5ce019e2 100644 --- a/examples/angular/router/package.json +++ b/examples/angular/router/package.json @@ -17,7 +17,7 @@ "@angular/platform-browser": "^17.3.3", "@angular/platform-browser-dynamic": "^17.3.3", "@angular/router": "^17.3.3", - "@tanstack/angular-query-experimental": "^5.30.0", + "@tanstack/angular-query-experimental": "^5.31.0", "rxjs": "^7.8.1", "tslib": "^2.6.2", "zone.js": "^0.14.4" @@ -26,7 +26,7 @@ "@angular-devkit/build-angular": "^17.3.3", "@angular/cli": "^17.3.3", "@angular/compiler-cli": "^17.3.3", - "@tanstack/angular-query-devtools-experimental": "^5.30.0", + "@tanstack/angular-query-devtools-experimental": "^5.31.0", "typescript": "5.2.2" } } diff --git a/examples/angular/simple/package.json b/examples/angular/simple/package.json index bb2cbf19bf..dbfce86db7 100644 --- a/examples/angular/simple/package.json +++ b/examples/angular/simple/package.json @@ -17,7 +17,7 @@ "@angular/platform-browser": "^17.3.3", "@angular/platform-browser-dynamic": "^17.3.3", "@angular/router": "^17.3.3", - "@tanstack/angular-query-experimental": "^5.30.0", + "@tanstack/angular-query-experimental": "^5.31.0", "rxjs": "^7.8.1", "tslib": "^2.6.2", "zone.js": "^0.14.4" @@ -26,7 +26,7 @@ "@angular-devkit/build-angular": "^17.3.3", "@angular/cli": "^17.3.3", "@angular/compiler-cli": "^17.3.3", - "@tanstack/angular-query-devtools-experimental": "^5.30.0", + "@tanstack/angular-query-devtools-experimental": "^5.31.0", "typescript": "5.2.2" } } diff --git a/examples/react/algolia/package.json b/examples/react/algolia/package.json index 4211c7a2f4..9608c31904 100644 --- a/examples/react/algolia/package.json +++ b/examples/react/algolia/package.json @@ -11,8 +11,8 @@ "dependencies": { "@algolia/client-search": "4.22.1", "@algolia/transporter": "4.22.1", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "algoliasearch": "4.22.1", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/auto-refetching/package.json b/examples/react/auto-refetching/package.json index 6ab6113f3d..5b6759da27 100644 --- a/examples/react/auto-refetching/package.json +++ b/examples/react/auto-refetching/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/basic-graphql-request/package.json b/examples/react/basic-graphql-request/package.json index 0856ea8961..40b67d5ba8 100644 --- a/examples/react/basic-graphql-request/package.json +++ b/examples/react/basic-graphql-request/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "graphql": "^16.8.1", "graphql-request": "^6.1.0", "react": "^18.2.0", diff --git a/examples/react/basic-typescript/package.json b/examples/react/basic-typescript/package.json index 171534c97e..74c6fcd4cf 100644 --- a/examples/react/basic-typescript/package.json +++ b/examples/react/basic-typescript/package.json @@ -9,10 +9,10 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/query-sync-storage-persister": "^5.29.0", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", - "@tanstack/react-query-persist-client": "^5.29.2", + "@tanstack/query-sync-storage-persister": "^5.31.0", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", + "@tanstack/react-query-persist-client": "^5.31.0", "axios": "^1.6.7", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/basic/package.json b/examples/react/basic/package.json index dac4981136..e7425f4fc2 100644 --- a/examples/react/basic/package.json +++ b/examples/react/basic/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/default-query-function/package.json b/examples/react/default-query-function/package.json index 96a908914a..2c5d8e4a93 100644 --- a/examples/react/default-query-function/package.json +++ b/examples/react/default-query-function/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/infinite-query-with-max-pages/package.json b/examples/react/infinite-query-with-max-pages/package.json index d8a905497e..405f26b382 100644 --- a/examples/react/infinite-query-with-max-pages/package.json +++ b/examples/react/infinite-query-with-max-pages/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/load-more-infinite-scroll/package.json b/examples/react/load-more-infinite-scroll/package.json index 854ab33ced..81e202ef65 100644 --- a/examples/react/load-more-infinite-scroll/package.json +++ b/examples/react/load-more-infinite-scroll/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/nextjs-suspense-streaming/package.json b/examples/react/nextjs-suspense-streaming/package.json index e3cbe64f96..67a9311421 100644 --- a/examples/react/nextjs-suspense-streaming/package.json +++ b/examples/react/nextjs-suspense-streaming/package.json @@ -8,9 +8,9 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", - "@tanstack/react-query-next-experimental": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", + "@tanstack/react-query-next-experimental": "^5.31.0", "next": "^14.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/examples/react/nextjs/package.json b/examples/react/nextjs/package.json index b7316045fa..ecae9601c7 100644 --- a/examples/react/nextjs/package.json +++ b/examples/react/nextjs/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "ky": "^1.2.0", "next": "^14.0.0", "react": "^18.2.0", diff --git a/examples/react/offline/package.json b/examples/react/offline/package.json index 8205710636..8f68d1e776 100644 --- a/examples/react/offline/package.json +++ b/examples/react/offline/package.json @@ -8,11 +8,11 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/query-sync-storage-persister": "^5.29.0", + "@tanstack/query-sync-storage-persister": "^5.31.0", "@tanstack/react-location": "^3.7.4", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", - "@tanstack/react-query-persist-client": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", + "@tanstack/react-query-persist-client": "^5.31.0", "ky": "^1.2.0", "msw": "^2.1.7", "react": "^18.2.0", diff --git a/examples/react/optimistic-updates-cache/package.json b/examples/react/optimistic-updates-cache/package.json index c8a4ea8e2b..b90477ab12 100755 --- a/examples/react/optimistic-updates-cache/package.json +++ b/examples/react/optimistic-updates-cache/package.json @@ -8,8 +8,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/optimistic-updates-ui/package.json b/examples/react/optimistic-updates-ui/package.json index 3c4f0be498..e36d370f52 100755 --- a/examples/react/optimistic-updates-ui/package.json +++ b/examples/react/optimistic-updates-ui/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/pagination/package.json b/examples/react/pagination/package.json index 808fa37e4f..b15631e7c3 100644 --- a/examples/react/pagination/package.json +++ b/examples/react/pagination/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/playground/package.json b/examples/react/playground/package.json index 846f3cff36..2a9d69177d 100644 --- a/examples/react/playground/package.json +++ b/examples/react/playground/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react/prefetching/package.json b/examples/react/prefetching/package.json index b362d78d8d..5deca35812 100644 --- a/examples/react/prefetching/package.json +++ b/examples/react/prefetching/package.json @@ -7,8 +7,8 @@ "start": "next start" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "isomorphic-unfetch": "4.0.2", "next": "^14.0.0", diff --git a/examples/react/react-native/package.json b/examples/react/react-native/package.json index edbae0ff66..d44581da82 100644 --- a/examples/react/react-native/package.json +++ b/examples/react/react-native/package.json @@ -14,8 +14,8 @@ "@react-native-community/netinfo": "^11.1.0", "@react-navigation/native": "^6.1.6", "@react-navigation/stack": "^6.3.16", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "expo": "^50.0.6", "expo-constants": "^15.4.5", "expo-status-bar": "^1.11.1", diff --git a/examples/react/react-router/package.json b/examples/react/react-router/package.json index f02023c609..aada1687a4 100644 --- a/examples/react/react-router/package.json +++ b/examples/react/react-router/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "localforage": "^1.10.0", "match-sorter": "^6.3.4", "react": "^18.2.0", diff --git a/examples/react/rick-morty/package.json b/examples/react/rick-morty/package.json index 9010b792df..3dea4aa817 100644 --- a/examples/react/rick-morty/package.json +++ b/examples/react/rick-morty/package.json @@ -12,8 +12,8 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.2", "@mui/styles": "^5.15.2", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router": "^6.22.0", diff --git a/examples/react/shadow-dom/package.json b/examples/react/shadow-dom/package.json index 4bdd0641d6..bab2ce1b8d 100644 --- a/examples/react/shadow-dom/package.json +++ b/examples/react/shadow-dom/package.json @@ -10,8 +10,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/react/simple/package.json b/examples/react/simple/package.json index a36a4ba04d..31e3c95705 100644 --- a/examples/react/simple/package.json +++ b/examples/react/simple/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "react": "^18.2.0", "react-dom": "^18.2.0" diff --git a/examples/react/star-wars/package.json b/examples/react/star-wars/package.json index 92c68857ce..3647bd2113 100644 --- a/examples/react/star-wars/package.json +++ b/examples/react/star-wars/package.json @@ -12,8 +12,8 @@ "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.2", "@mui/styles": "^5.15.2", - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router": "^6.22.0", diff --git a/examples/react/suspense/package.json b/examples/react/suspense/package.json index 6ab7e387f7..b426039d2e 100644 --- a/examples/react/suspense/package.json +++ b/examples/react/suspense/package.json @@ -3,8 +3,8 @@ "private": true, "type": "module", "dependencies": { - "@tanstack/react-query": "^5.29.2", - "@tanstack/react-query-devtools": "^5.29.2", + "@tanstack/react-query": "^5.31.0", + "@tanstack/react-query-devtools": "^5.31.0", "axios": "^1.6.7", "font-awesome": "^4.7.0", "react": "^18.2.0", diff --git a/examples/solid/astro/package.json b/examples/solid/astro/package.json index fee7a80dd0..ae768a1edf 100644 --- a/examples/solid/astro/package.json +++ b/examples/solid/astro/package.json @@ -15,8 +15,8 @@ "@astrojs/tailwind": "^5.1.0", "@astrojs/vercel": "^7.5.3", "@astrojs/node": "^8.2.5", - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "astro": "^4.6.1", "solid-js": "^1.8.14", "tailwindcss": "^3.4.1", diff --git a/examples/solid/basic-graphql-request/package.json b/examples/solid/basic-graphql-request/package.json index 21f32d24d6..83dc21be4f 100644 --- a/examples/solid/basic-graphql-request/package.json +++ b/examples/solid/basic-graphql-request/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "graphql": "^16.8.1", "graphql-request": "^6.1.0", "solid-js": "^1.8.14" diff --git a/examples/solid/basic-typescript/package.json b/examples/solid/basic-typescript/package.json index 501d3bf89f..dcdd5caf36 100644 --- a/examples/solid/basic-typescript/package.json +++ b/examples/solid/basic-typescript/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "solid-js": "^1.8.14" }, "devDependencies": { diff --git a/examples/solid/default-query-function/package.json b/examples/solid/default-query-function/package.json index 65f7e83f5e..571e3b29d5 100644 --- a/examples/solid/default-query-function/package.json +++ b/examples/solid/default-query-function/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "solid-js": "^1.8.14" }, "devDependencies": { diff --git a/examples/solid/simple/package.json b/examples/solid/simple/package.json index 5116012f59..b50ed04fc3 100644 --- a/examples/solid/simple/package.json +++ b/examples/solid/simple/package.json @@ -9,8 +9,8 @@ "test:types": "tsc" }, "dependencies": { - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "solid-js": "^1.8.14" }, "devDependencies": { diff --git a/examples/solid/solid-start-streaming/package.json b/examples/solid/solid-start-streaming/package.json index 40949f868f..5c0a0ae3d0 100644 --- a/examples/solid/solid-start-streaming/package.json +++ b/examples/solid/solid-start-streaming/package.json @@ -11,8 +11,8 @@ "@solidjs/meta": "^0.29.2", "@solidjs/router": "^0.13.2", "@solidjs/start": "^1.0.0-rc.0", - "@tanstack/solid-query": "^5.30.6", - "@tanstack/solid-query-devtools": "^5.30.6", + "@tanstack/solid-query": "^5.31.0", + "@tanstack/solid-query-devtools": "^5.31.0", "solid-js": "^1.8.14", "vinxi": "^0.3.10" }, diff --git a/examples/svelte/auto-refetching/package.json b/examples/svelte/auto-refetching/package.json index 08b94b0be0..1d7cadda1d 100644 --- a/examples/svelte/auto-refetching/package.json +++ b/examples/svelte/auto-refetching/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/basic/package.json b/examples/svelte/basic/package.json index 2c88c02e1b..190a1165d1 100644 --- a/examples/svelte/basic/package.json +++ b/examples/svelte/basic/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/load-more-infinite-scroll/package.json b/examples/svelte/load-more-infinite-scroll/package.json index 8efb4b217f..daf9344514 100644 --- a/examples/svelte/load-more-infinite-scroll/package.json +++ b/examples/svelte/load-more-infinite-scroll/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/optimistic-updates-typescript/package.json b/examples/svelte/optimistic-updates-typescript/package.json index 3a16dcc457..840e23ca99 100644 --- a/examples/svelte/optimistic-updates-typescript/package.json +++ b/examples/svelte/optimistic-updates-typescript/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/playground/package.json b/examples/svelte/playground/package.json index 0a86a7e60a..e3116bf97e 100644 --- a/examples/svelte/playground/package.json +++ b/examples/svelte/playground/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/simple/package.json b/examples/svelte/simple/package.json index fda9225e9f..0df9daae68 100644 --- a/examples/svelte/simple/package.json +++ b/examples/svelte/simple/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.2", diff --git a/examples/svelte/ssr/package.json b/examples/svelte/ssr/package.json index 69d18fc8a5..9876e0aa82 100644 --- a/examples/svelte/ssr/package.json +++ b/examples/svelte/ssr/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/svelte/star-wars/package.json b/examples/svelte/star-wars/package.json index ef2ae13753..cdb938e362 100644 --- a/examples/svelte/star-wars/package.json +++ b/examples/svelte/star-wars/package.json @@ -9,8 +9,8 @@ "test:types": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, "dependencies": { - "@tanstack/svelte-query": "^5.29.0", - "@tanstack/svelte-query-devtools": "^5.29.0" + "@tanstack/svelte-query": "^5.31.0", + "@tanstack/svelte-query-devtools": "^5.31.0" }, "devDependencies": { "@sveltejs/adapter-auto": "^3.1.1", diff --git a/examples/vue/2.6-basic/package.json b/examples/vue/2.6-basic/package.json index d4bfc420ab..4048e62fae 100644 --- a/examples/vue/2.6-basic/package.json +++ b/examples/vue/2.6-basic/package.json @@ -8,7 +8,7 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0", + "@tanstack/vue-query": "^5.31.0", "@vue/composition-api": "1.7.2", "vue": "2.6.14", "vue-template-compiler": "2.6.14" diff --git a/examples/vue/2.7-basic/package.json b/examples/vue/2.7-basic/package.json index e1e9019814..e5ca750f90 100644 --- a/examples/vue/2.7-basic/package.json +++ b/examples/vue/2.7-basic/package.json @@ -8,7 +8,7 @@ "serve": "vite preview" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0", + "@tanstack/vue-query": "^5.31.0", "vue": "2.7.16", "vue-template-compiler": "2.7.16" }, diff --git a/examples/vue/basic/package.json b/examples/vue/basic/package.json index 458afe473f..5172dcb670 100644 --- a/examples/vue/basic/package.json +++ b/examples/vue/basic/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0", - "@tanstack/vue-query-devtools": "^5.29.0", + "@tanstack/vue-query": "^5.31.0", + "@tanstack/vue-query-devtools": "^5.31.0", "vue": "^3.3.0" }, "devDependencies": { diff --git a/examples/vue/dependent-queries/package.json b/examples/vue/dependent-queries/package.json index 23ad0c99e1..98b1916028 100644 --- a/examples/vue/dependent-queries/package.json +++ b/examples/vue/dependent-queries/package.json @@ -8,7 +8,7 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0", + "@tanstack/vue-query": "^5.31.0", "vue": "^3.3.0" }, "devDependencies": { diff --git a/examples/vue/nuxt3/package.json b/examples/vue/nuxt3/package.json index 0162ece623..86eb8f26a8 100644 --- a/examples/vue/nuxt3/package.json +++ b/examples/vue/nuxt3/package.json @@ -7,7 +7,7 @@ "start": "node .output/server/index.mjs" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0" + "@tanstack/vue-query": "^5.31.0" }, "devDependencies": { "nuxt": "^3.5.2" diff --git a/examples/vue/persister/package.json b/examples/vue/persister/package.json index b7a846199d..56145813af 100644 --- a/examples/vue/persister/package.json +++ b/examples/vue/persister/package.json @@ -8,10 +8,10 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/query-core": "^5.29.0", - "@tanstack/query-persist-client-core": "^5.29.0", - "@tanstack/query-sync-storage-persister": "^5.29.0", - "@tanstack/vue-query": "^5.29.0", + "@tanstack/query-core": "^5.31.0", + "@tanstack/query-persist-client-core": "^5.31.0", + "@tanstack/query-sync-storage-persister": "^5.31.0", + "@tanstack/vue-query": "^5.31.0", "idb-keyval": "^6.2.1", "vue": "^3.3.0" }, diff --git a/examples/vue/simple/package.json b/examples/vue/simple/package.json index 06a02d6833..b707c1d4f2 100644 --- a/examples/vue/simple/package.json +++ b/examples/vue/simple/package.json @@ -8,8 +8,8 @@ "preview": "vite preview" }, "dependencies": { - "@tanstack/vue-query": "^5.29.0", - "@tanstack/vue-query-devtools": "^5.29.0", + "@tanstack/vue-query": "^5.31.0", + "@tanstack/vue-query-devtools": "^5.31.0", "vue": "^3.3.0" }, "devDependencies": { diff --git a/packages/angular-query-devtools-experimental/package.json b/packages/angular-query-devtools-experimental/package.json index eb45a4efb1..5e3b1af9d9 100644 --- a/packages/angular-query-devtools-experimental/package.json +++ b/packages/angular-query-devtools-experimental/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/angular-query-devtools-experimental", - "version": "5.30.0", + "version": "5.31.0", "description": "Developer tools to interact with and visualize the TanStack/angular-query cache", "author": "Arnoud de Vries", "license": "MIT", diff --git a/packages/angular-query-experimental/package.json b/packages/angular-query-experimental/package.json index 17f251a877..c892864cb0 100644 --- a/packages/angular-query-experimental/package.json +++ b/packages/angular-query-experimental/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/angular-query-experimental", - "version": "5.30.0", + "version": "5.31.0", "description": "Signals for managing, caching and syncing asynchronous and remote data in Angular", "author": "Arnoud de Vries", "license": "MIT", diff --git a/packages/query-async-storage-persister/package.json b/packages/query-async-storage-persister/package.json index aa3e1e2920..c5d5e063d0 100644 --- a/packages/query-async-storage-persister/package.json +++ b/packages/query-async-storage-persister/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-async-storage-persister", - "version": "5.29.1", + "version": "5.31.0", "description": "A persister for asynchronous storages, to be used with TanStack/Query", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/query-broadcast-client-experimental/package.json b/packages/query-broadcast-client-experimental/package.json index d6a9205d3c..ff67bd4106 100644 --- a/packages/query-broadcast-client-experimental/package.json +++ b/packages/query-broadcast-client-experimental/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-broadcast-client-experimental", - "version": "5.29.0", + "version": "5.31.0", "description": "An experimental plugin to for broadcasting the state of your queryClient between browser tabs/windows", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/query-core/package.json b/packages/query-core/package.json index a25806acb2..b818f5adad 100644 --- a/packages/query-core/package.json +++ b/packages/query-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-core", - "version": "5.29.0", + "version": "5.31.0", "description": "The framework agnostic core that powers TanStack Query", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/query-core/src/__tests__/hydration.test.tsx b/packages/query-core/src/__tests__/hydration.test.tsx index d4a00b1dd7..45d67d148e 100644 --- a/packages/query-core/src/__tests__/hydration.test.tsx +++ b/packages/query-core/src/__tests__/hydration.test.tsx @@ -704,4 +704,38 @@ describe('dehydration and rehydration', () => { hydrationCache.find({ queryKey: ['string'] })?.state.fetchStatus, ).toBe('idle') }) + + test('should dehydrate and hydrate mutation scopes', async () => { + const queryClient = createQueryClient() + const onlineMock = mockOnlineManagerIsOnline(false) + + void executeMutation( + queryClient, + { + mutationKey: ['mutation'], + mutationFn: async () => { + return 'mutation' + }, + scope: { + id: 'scope', + }, + }, + 'vars', + ) + + const dehydrated = dehydrate(queryClient) + expect(dehydrated.mutations[0]?.scope?.id).toBe('scope') + const stringified = JSON.stringify(dehydrated) + + // --- + const parsed = JSON.parse(stringified) + const hydrationCache = new MutationCache() + const hydrationClient = createQueryClient({ mutationCache: hydrationCache }) + + hydrate(hydrationClient, parsed) + + expect(dehydrated.mutations[0]?.scope?.id).toBe('scope') + + onlineMock.mockRestore() + }) }) diff --git a/packages/query-core/src/__tests__/mutations.test.tsx b/packages/query-core/src/__tests__/mutations.test.tsx index 9a93828b35..acf52658c9 100644 --- a/packages/query-core/src/__tests__/mutations.test.tsx +++ b/packages/query-core/src/__tests__/mutations.test.tsx @@ -409,4 +409,195 @@ describe('mutations', () => { expect(onSuccess).toHaveBeenCalledWith(2) }) + + describe('scoped mutations', () => { + test('mutations in the same scope should run in serial', async () => { + const key1 = queryKey() + const key2 = queryKey() + + const results: Array = [] + + const execute1 = executeMutation( + queryClient, + { + mutationKey: key1, + scope: { + id: 'scope', + }, + mutationFn: async () => { + results.push('start-A') + await sleep(10) + results.push('finish-A') + return 'a' + }, + }, + 'vars1', + ) + + expect( + queryClient.getMutationCache().find({ mutationKey: key1 })?.state, + ).toMatchObject({ + status: 'pending', + isPaused: false, + }) + + const execute2 = executeMutation( + queryClient, + { + mutationKey: key2, + scope: { + id: 'scope', + }, + mutationFn: async () => { + results.push('start-B') + await sleep(10) + results.push('finish-B') + return 'b' + }, + }, + 'vars2', + ) + + expect( + queryClient.getMutationCache().find({ mutationKey: key2 })?.state, + ).toMatchObject({ + status: 'pending', + isPaused: true, + }) + + await Promise.all([execute1, execute2]) + + expect(results).toStrictEqual([ + 'start-A', + 'finish-A', + 'start-B', + 'finish-B', + ]) + }) + }) + + test('mutations without scope should run in parallel', async () => { + const key1 = queryKey() + const key2 = queryKey() + + const results: Array = [] + + const execute1 = executeMutation( + queryClient, + { + mutationKey: key1, + mutationFn: async () => { + results.push('start-A') + await sleep(10) + results.push('finish-A') + return 'a' + }, + }, + 'vars1', + ) + + const execute2 = executeMutation( + queryClient, + { + mutationKey: key2, + mutationFn: async () => { + results.push('start-B') + await sleep(10) + results.push('finish-B') + return 'b' + }, + }, + 'vars2', + ) + + await Promise.all([execute1, execute2]) + + expect(results).toStrictEqual([ + 'start-A', + 'start-B', + 'finish-A', + 'finish-B', + ]) + }) + + test('each scope should run should run in parallel, serial within scope', async () => { + const results: Array = [] + + const execute1 = executeMutation( + queryClient, + { + scope: { + id: '1', + }, + mutationFn: async () => { + results.push('start-A1') + await sleep(10) + results.push('finish-A1') + return 'a' + }, + }, + 'vars1', + ) + + const execute2 = executeMutation( + queryClient, + { + scope: { + id: '1', + }, + mutationFn: async () => { + results.push('start-B1') + await sleep(10) + results.push('finish-B1') + return 'b' + }, + }, + 'vars2', + ) + + const execute3 = executeMutation( + queryClient, + { + scope: { + id: '2', + }, + mutationFn: async () => { + results.push('start-A2') + await sleep(10) + results.push('finish-A2') + return 'a' + }, + }, + 'vars1', + ) + + const execute4 = executeMutation( + queryClient, + { + scope: { + id: '2', + }, + mutationFn: async () => { + results.push('start-B2') + await sleep(10) + results.push('finish-B2') + return 'b' + }, + }, + 'vars2', + ) + + await Promise.all([execute1, execute2, execute3, execute4]) + + expect(results).toStrictEqual([ + 'start-A1', + 'start-A2', + 'finish-A1', + 'start-B1', + 'finish-A2', + 'start-B2', + 'finish-B1', + 'finish-B2', + ]) + }) }) diff --git a/packages/query-core/src/__tests__/queryClient.test.tsx b/packages/query-core/src/__tests__/queryClient.test.tsx index ef64f5a3dc..047d067327 100644 --- a/packages/query-core/src/__tests__/queryClient.test.tsx +++ b/packages/query-core/src/__tests__/queryClient.test.tsx @@ -1511,11 +1511,51 @@ describe('queryClient', () => { await waitFor(() => { expect(observer1.getCurrentResult().status).toBe('success') + expect(observer2.getCurrentResult().status).toBe('success') + }) + }) + + test('should resume paused mutations in parallel', async () => { + onlineManager.setOnline(false) + + const orders: Array = [] + + const observer1 = new MutationObserver(queryClient, { + mutationFn: async () => { + orders.push('1start') + await sleep(50) + orders.push('1end') + return 1 + }, + }) + + const observer2 = new MutationObserver(queryClient, { + mutationFn: async () => { + orders.push('2start') + await sleep(20) + orders.push('2end') + return 2 + }, + }) + void observer1.mutate() + void observer2.mutate() + + await waitFor(() => { + expect(observer1.getCurrentResult().isPaused).toBeTruthy() + expect(observer2.getCurrentResult().isPaused).toBeTruthy() + }) + + onlineManager.setOnline(true) + + await waitFor(() => { expect(observer1.getCurrentResult().status).toBe('success') + expect(observer2.getCurrentResult().status).toBe('success') }) + + expect(orders).toEqual(['1start', '2start', '2end', '1end']) }) - test('should resume paused mutations one after the other when invoked manually at the same time', async () => { + test('should resume paused mutations one after the other when in the same scope when invoked manually at the same time', async () => { const consoleMock = vi.spyOn(console, 'error') consoleMock.mockImplementation(() => undefined) onlineManager.setOnline(false) @@ -1523,6 +1563,9 @@ describe('queryClient', () => { const orders: Array = [] const observer1 = new MutationObserver(queryClient, { + scope: { + id: 'scope', + }, mutationFn: async () => { orders.push('1start') await sleep(50) @@ -1532,6 +1575,9 @@ describe('queryClient', () => { }) const observer2 = new MutationObserver(queryClient, { + scope: { + id: 'scope', + }, mutationFn: async () => { orders.push('2start') await sleep(20) @@ -1656,15 +1702,52 @@ describe('queryClient', () => { const observer = new MutationObserver(queryClient, { mutationFn: async () => { - results.push('mutation') + results.push('mutation1-start') await sleep(50) + results.push('mutation1-end') return 1 }, }) void observer.mutate() - expect(observer.getCurrentResult().isPaused).toBeTruthy() + const observer2 = new MutationObserver(queryClient, { + scope: { + id: 'scope', + }, + mutationFn: async () => { + results.push('mutation2-start') + await sleep(50) + results.push('mutation2-end') + return 2 + }, + }) + + void observer2.mutate() + + const observer3 = new MutationObserver(queryClient, { + scope: { + id: 'scope', + }, + mutationFn: async () => { + results.push('mutation3-start') + await sleep(50) + results.push('mutation3-end') + return 3 + }, + }) + + void observer3.mutate() + + await waitFor(() => + expect(observer.getCurrentResult().isPaused).toBeTruthy(), + ) + await waitFor(() => + expect(observer2.getCurrentResult().isPaused).toBeTruthy(), + ) + await waitFor(() => + expect(observer3.getCurrentResult().isPaused).toBeTruthy(), + ) onlineManager.setOnline(true) @@ -1673,7 +1756,16 @@ describe('queryClient', () => { }) // refetch from coming online should happen after mutations have finished - expect(results).toStrictEqual(['data1', 'mutation', 'data2']) + expect(results).toStrictEqual([ + 'data1', + 'mutation1-start', + 'mutation2-start', + 'mutation1-end', + 'mutation2-end', + 'mutation3-start', // 3 starts after 2 because they are in the same scope + 'mutation3-end', + 'data2', + ]) unsubscribe() }) diff --git a/packages/query-core/src/hydration.ts b/packages/query-core/src/hydration.ts index 4e6b58e4f0..0b0f090686 100644 --- a/packages/query-core/src/hydration.ts +++ b/packages/query-core/src/hydration.ts @@ -1,13 +1,14 @@ -import type { QueryClient } from './queryClient' -import type { Query, QueryState } from './query' import type { MutationKey, MutationMeta, MutationOptions, + MutationScope, QueryKey, QueryMeta, QueryOptions, } from './types' +import type { QueryClient } from './queryClient' +import type { Query, QueryState } from './query' import type { Mutation, MutationState } from './mutation' // TYPES @@ -28,6 +29,7 @@ interface DehydratedMutation { mutationKey?: MutationKey state: MutationState meta?: MutationMeta + scope?: MutationScope } interface DehydratedQuery { @@ -48,6 +50,7 @@ function dehydrateMutation(mutation: Mutation): DehydratedMutation { return { mutationKey: mutation.options.mutationKey, state: mutation.state, + ...(mutation.options.scope && { scope: mutation.options.scope }), ...(mutation.meta && { meta: mutation.meta }), } } @@ -115,15 +118,14 @@ export function hydrate( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition const queries = (dehydratedState as DehydratedState).queries || [] - mutations.forEach((dehydratedMutation) => { + mutations.forEach(({ state, ...mutationOptions }) => { mutationCache.build( client, { ...options?.defaultOptions?.mutations, - mutationKey: dehydratedMutation.mutationKey, - meta: dehydratedMutation.meta, + ...mutationOptions, }, - dehydratedMutation.state, + state, ) }) diff --git a/packages/query-core/src/mutation.ts b/packages/query-core/src/mutation.ts index 79d87c0d73..69f9d6286b 100644 --- a/packages/query-core/src/mutation.ts +++ b/packages/query-core/src/mutation.ts @@ -1,6 +1,6 @@ import { notifyManager } from './notifyManager' import { Removable } from './removable' -import { canFetch, createRetryer } from './retryer' +import { createRetryer } from './retryer' import type { DefaultError, MutationMeta, @@ -17,7 +17,6 @@ interface MutationConfig { mutationId: number mutationCache: MutationCache options: MutationOptions - defaultOptions?: MutationOptions state?: MutationState } @@ -46,6 +45,7 @@ interface FailedAction { interface PendingAction { type: 'pending' + isPaused: boolean variables?: TVariables context?: TContext } @@ -89,7 +89,6 @@ export class Mutation< readonly mutationId: number #observers: Array> - #defaultOptions?: MutationOptions #mutationCache: MutationCache #retryer?: Retryer @@ -97,7 +96,6 @@ export class Mutation< super() this.mutationId = config.mutationId - this.#defaultOptions = config.defaultOptions this.#mutationCache = config.mutationCache this.#observers = [] this.state = config.state || getDefaultState() @@ -107,9 +105,9 @@ export class Mutation< } setOptions( - options?: MutationOptions, + options: MutationOptions, ): void { - this.options = { ...this.#defaultOptions, ...options } + this.options = options this.updateGcTime(this.options.gcTime) } @@ -164,36 +162,34 @@ export class Mutation< } async execute(variables: TVariables): Promise { - const executeMutation = () => { - this.#retryer = createRetryer({ - fn: () => { - if (!this.options.mutationFn) { - return Promise.reject(new Error('No mutationFn found')) - } - return this.options.mutationFn(variables) - }, - onFail: (failureCount, error) => { - this.#dispatch({ type: 'failed', failureCount, error }) - }, - onPause: () => { - this.#dispatch({ type: 'pause' }) - }, - onContinue: () => { - this.#dispatch({ type: 'continue' }) - }, - retry: this.options.retry ?? 0, - retryDelay: this.options.retryDelay, - networkMode: this.options.networkMode, - }) - - return this.#retryer.promise - } + this.#retryer = createRetryer({ + fn: () => { + if (!this.options.mutationFn) { + return Promise.reject(new Error('No mutationFn found')) + } + return this.options.mutationFn(variables) + }, + onFail: (failureCount, error) => { + this.#dispatch({ type: 'failed', failureCount, error }) + }, + onPause: () => { + this.#dispatch({ type: 'pause' }) + }, + onContinue: () => { + this.#dispatch({ type: 'continue' }) + }, + retry: this.options.retry ?? 0, + retryDelay: this.options.retryDelay, + networkMode: this.options.networkMode, + canRun: () => this.#mutationCache.canRun(this), + }) const restored = this.state.status === 'pending' + const isPaused = !this.#retryer.canStart() try { if (!restored) { - this.#dispatch({ type: 'pending', variables }) + this.#dispatch({ type: 'pending', variables, isPaused }) // Notify cache callback await this.#mutationCache.config.onMutate?.( variables, @@ -205,10 +201,11 @@ export class Mutation< type: 'pending', context, variables, + isPaused, }) } } - const data = await executeMutation() + const data = await this.#retryer.start() // Notify cache callback await this.#mutationCache.config.onSuccess?.( @@ -268,6 +265,8 @@ export class Mutation< } finally { this.#dispatch({ type: 'error', error: error as TError }) } + } finally { + this.#mutationCache.runNext(this) } } @@ -300,7 +299,7 @@ export class Mutation< failureCount: 0, failureReason: null, error: null, - isPaused: !canFetch(this.options.networkMode), + isPaused: action.isPaused, status: 'pending', variables: action.variables, submittedAt: Date.now(), diff --git a/packages/query-core/src/mutationCache.ts b/packages/query-core/src/mutationCache.ts index 628b63e1ed..1663b50cef 100644 --- a/packages/query-core/src/mutationCache.ts +++ b/packages/query-core/src/mutationCache.ts @@ -82,14 +82,13 @@ type MutationCacheListener = (event: MutationCacheNotifyEvent) => void // CLASS export class MutationCache extends Subscribable { - #mutations: Array> + #mutations: Map>> #mutationId: number - #resuming: Promise | undefined constructor(public config: MutationCacheConfig = {}) { super() - this.#mutations = [] - this.#mutationId = 0 + this.#mutations = new Map() + this.#mutationId = Date.now() } build( @@ -110,25 +109,59 @@ export class MutationCache extends Subscribable { } add(mutation: Mutation): void { - this.#mutations.push(mutation) + const scope = scopeFor(mutation) + const mutations = this.#mutations.get(scope) ?? [] + mutations.push(mutation) + this.#mutations.set(scope, mutations) this.notify({ type: 'added', mutation }) } remove(mutation: Mutation): void { - this.#mutations = this.#mutations.filter((x) => x !== mutation) + const scope = scopeFor(mutation) + if (this.#mutations.has(scope)) { + const mutations = this.#mutations + .get(scope) + ?.filter((x) => x !== mutation) + if (mutations) { + if (mutations.length === 0) { + this.#mutations.delete(scope) + } else { + this.#mutations.set(scope, mutations) + } + } + } + this.notify({ type: 'removed', mutation }) } + canRun(mutation: Mutation): boolean { + const firstPendingMutation = this.#mutations + .get(scopeFor(mutation)) + ?.find((m) => m.state.status === 'pending') + + // we can run if there is no current pending mutation (start use-case) + // or if WE are the first pending mutation (continue use-case) + return !firstPendingMutation || firstPendingMutation === mutation + } + + runNext(mutation: Mutation): Promise { + const foundMutation = this.#mutations + .get(scopeFor(mutation)) + ?.find((m) => m !== mutation && m.state.isPaused) + + return foundMutation?.continue() ?? Promise.resolve() + } + clear(): void { notifyManager.batch(() => { - this.#mutations.forEach((mutation) => { + this.getAll().forEach((mutation) => { this.remove(mutation) }) }) } getAll(): Array { - return this.#mutations + return [...this.#mutations.values()].flat() } find< @@ -141,15 +174,13 @@ export class MutationCache extends Subscribable { ): Mutation | undefined { const defaultedFilters = { exact: true, ...filters } - return this.#mutations.find((mutation) => + return this.getAll().find((mutation) => matchMutation(defaultedFilters, mutation), - ) + ) as Mutation | undefined } findAll(filters: MutationFilters = {}): Array { - return this.#mutations.filter((mutation) => - matchMutation(filters, mutation), - ) + return this.getAll().filter((mutation) => matchMutation(filters, mutation)) } notify(event: MutationCacheNotifyEvent) { @@ -161,21 +192,16 @@ export class MutationCache extends Subscribable { } resumePausedMutations(): Promise { - this.#resuming = (this.#resuming ?? Promise.resolve()) - .then(() => { - const pausedMutations = this.#mutations.filter((x) => x.state.isPaused) - return notifyManager.batch(() => - pausedMutations.reduce( - (promise, mutation) => - promise.then(() => mutation.continue().catch(noop)), - Promise.resolve() as Promise, - ), - ) - }) - .then(() => { - this.#resuming = undefined - }) + const pausedMutations = this.getAll().filter((x) => x.state.isPaused) - return this.#resuming + return notifyManager.batch(() => + Promise.all( + pausedMutations.map((mutation) => mutation.continue().catch(noop)), + ), + ) } } + +function scopeFor(mutation: Mutation) { + return mutation.options.scope?.id ?? String(mutation.mutationId) +} diff --git a/packages/query-core/src/query.ts b/packages/query-core/src/query.ts index 5cfaa23561..21c1a7cb5e 100644 --- a/packages/query-core/src/query.ts +++ b/packages/query-core/src/query.ts @@ -527,9 +527,10 @@ export class Query< retry: context.options.retry, retryDelay: context.options.retryDelay, networkMode: context.options.networkMode, + canRun: () => true, }) - return this.#retryer.promise + return this.#retryer.start() } #dispatch(action: Action): void { diff --git a/packages/query-core/src/retryer.ts b/packages/query-core/src/retryer.ts index 3a0dace821..fb1584aad9 100644 --- a/packages/query-core/src/retryer.ts +++ b/packages/query-core/src/retryer.ts @@ -16,6 +16,7 @@ interface RetryerConfig { retry?: RetryValue retryDelay?: RetryDelayValue networkMode: NetworkMode | undefined + canRun: () => boolean } export interface Retryer { @@ -24,6 +25,8 @@ export interface Retryer { continue: () => Promise cancelRetry: () => void continueRetry: () => void + canStart: () => boolean + start: () => Promise } export type RetryValue = boolean | number | ShouldRetryFunction @@ -69,7 +72,7 @@ export function createRetryer( let isRetryCancelled = false let failureCount = 0 let isResolved = false - let continueFn: ((value?: unknown) => boolean) | undefined + let continueFn: ((value?: unknown) => void) | undefined let promiseResolve: (data: TData) => void let promiseReject: (error: TError) => void @@ -93,9 +96,12 @@ export function createRetryer( isRetryCancelled = false } - const shouldPause = () => - !focusManager.isFocused() || - (config.networkMode !== 'always' && !onlineManager.isOnline()) + const canContinue = () => + focusManager.isFocused() && + (config.networkMode === 'always' || onlineManager.isOnline()) && + config.canRun() + + const canStart = () => canFetch(config.networkMode) && config.canRun() const resolve = (value: any) => { if (!isResolved) { @@ -118,11 +124,9 @@ export function createRetryer( const pause = () => { return new Promise((continueResolve) => { continueFn = (value) => { - const canContinue = isResolved || !shouldPause() - if (canContinue) { + if (isResolved || canContinue()) { continueResolve(value) } - return canContinue } config.onPause?.() }).then(() => { @@ -184,10 +188,7 @@ export function createRetryer( sleep(delay) // Pause if the document is not visible or when the device is offline .then(() => { - if (shouldPause()) { - return pause() - } - return + return canContinue() ? undefined : pause() }) .then(() => { if (isRetryCancelled) { @@ -199,21 +200,24 @@ export function createRetryer( }) } - // Start loop - if (canFetch(config.networkMode)) { - run() - } else { - pause().then(run) - } - return { promise, cancel, continue: () => { - const didContinue = continueFn?.() - return didContinue ? promise : Promise.resolve() + continueFn?.() + return promise }, cancelRetry, continueRetry, + canStart, + start: () => { + // Start loop + if (canStart()) { + run() + } else { + pause().then(run) + } + return promise + }, } } diff --git a/packages/query-core/src/types.ts b/packages/query-core/src/types.ts index 71fb6e1bf5..fd95ac2e24 100644 --- a/packages/query-core/src/types.ts +++ b/packages/query-core/src/types.ts @@ -717,6 +717,10 @@ export type MutationKey = ReadonlyArray export type MutationStatus = 'idle' | 'pending' | 'success' | 'error' +export type MutationScope = { + id: string +} + export type MutationMeta = Register extends { mutationMeta: infer TMutationMeta } @@ -762,6 +766,7 @@ export interface MutationOptions< gcTime?: number _defaulted?: boolean meta?: MutationMeta + scope?: MutationScope } export interface MutationObserverOptions< diff --git a/packages/query-persist-client-core/package.json b/packages/query-persist-client-core/package.json index 46ecaa83eb..f335e8c1dd 100644 --- a/packages/query-persist-client-core/package.json +++ b/packages/query-persist-client-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-persist-client-core", - "version": "5.29.0", + "version": "5.31.0", "description": "Set of utilities for interacting with persisters, which can save your queryClient for later use", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/query-sync-storage-persister/package.json b/packages/query-sync-storage-persister/package.json index 74b4528529..6d8b3b8285 100644 --- a/packages/query-sync-storage-persister/package.json +++ b/packages/query-sync-storage-persister/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/query-sync-storage-persister", - "version": "5.29.0", + "version": "5.31.0", "description": "A persister for synchronous storages, to be used with TanStack/Query", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-query-devtools/package.json b/packages/react-query-devtools/package.json index 74302bd08f..a49f448f98 100644 --- a/packages/react-query-devtools/package.json +++ b/packages/react-query-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-query-devtools", - "version": "5.29.2", + "version": "5.31.0", "description": "Developer tools to interact with and visualize the TanStack/react-query cache", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-query-next-experimental/package.json b/packages/react-query-next-experimental/package.json index 53e152705a..e4c1bc7fe0 100644 --- a/packages/react-query-next-experimental/package.json +++ b/packages/react-query-next-experimental/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-query-next-experimental", - "version": "5.29.2", + "version": "5.31.0", "description": "Hydration utils for React Query in the NextJs app directory", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-query-persist-client/package.json b/packages/react-query-persist-client/package.json index 739d1a58b8..5110be294c 100644 --- a/packages/react-query-persist-client/package.json +++ b/packages/react-query-persist-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-query-persist-client", - "version": "5.29.2", + "version": "5.31.0", "description": "React bindings to work with persisters in TanStack/react-query", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-query/package.json b/packages/react-query/package.json index 01c9a0161e..02002646bd 100644 --- a/packages/react-query/package.json +++ b/packages/react-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-query", - "version": "5.29.2", + "version": "5.31.0", "description": "Hooks for managing, caching and syncing asynchronous and remote data in React", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/react-query/src/__tests__/useMutation.test.tsx b/packages/react-query/src/__tests__/useMutation.test.tsx index 49ab1d632b..a57fe6cba9 100644 --- a/packages/react-query/src/__tests__/useMutation.test.tsx +++ b/packages/react-query/src/__tests__/useMutation.test.tsx @@ -592,7 +592,7 @@ describe('useMutation', () => { await sleep(10) count++ return count > 1 - ? Promise.resolve('data') + ? Promise.resolve(`data${count}`) : Promise.reject(new Error('oops')) }, retry: 1, @@ -631,7 +631,7 @@ describe('useMutation', () => { onlineMock.mockReturnValue(true) queryClient.getMutationCache().resumePausedMutations() - await waitFor(() => rendered.getByText('data: data')) + await waitFor(() => rendered.getByText('data: data2')) expect( queryClient.getMutationCache().findAll({ mutationKey: key })[0]?.state, @@ -640,7 +640,7 @@ describe('useMutation', () => { isPaused: false, failureCount: 0, failureReason: null, - data: 'data', + data: 'data2', }) onlineMock.mockRestore() diff --git a/packages/solid-query-devtools/package.json b/packages/solid-query-devtools/package.json index 2f55c0bba0..398c78216e 100644 --- a/packages/solid-query-devtools/package.json +++ b/packages/solid-query-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-query-devtools", - "version": "5.30.6", + "version": "5.31.0", "description": "Developer tools to interact with and visualize the TanStack/solid-query Query cache", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/solid-query-persist-client/package.json b/packages/solid-query-persist-client/package.json index f08488358d..81b2663f21 100644 --- a/packages/solid-query-persist-client/package.json +++ b/packages/solid-query-persist-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-query-persist-client", - "version": "5.30.6", + "version": "5.31.0", "description": "Solid.js bindings to work with persisters in TanStack/solid-query", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/solid-query/package.json b/packages/solid-query/package.json index ed313154a2..0717f8bf16 100644 --- a/packages/solid-query/package.json +++ b/packages/solid-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-query", - "version": "5.30.6", + "version": "5.31.0", "description": "Primitives for managing, caching and syncing asynchronous and remote data in Solid", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/svelte-query-devtools/package.json b/packages/svelte-query-devtools/package.json index 469ba710cd..ed824b9c13 100644 --- a/packages/svelte-query-devtools/package.json +++ b/packages/svelte-query-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/svelte-query-devtools", - "version": "5.29.0", + "version": "5.31.0", "description": "Developer tools to interact with and visualize the TanStack/svelte-query cache", "author": "Lachlan Collins", "license": "MIT", diff --git a/packages/svelte-query-persist-client/package.json b/packages/svelte-query-persist-client/package.json index 4d3a098559..57d4500d78 100644 --- a/packages/svelte-query-persist-client/package.json +++ b/packages/svelte-query-persist-client/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/svelte-query-persist-client", - "version": "5.29.0", + "version": "5.31.0", "description": "Svelte bindings to work with persisters in TanStack/svelte-query", "author": "Lachlan Collins", "license": "MIT", diff --git a/packages/svelte-query/package.json b/packages/svelte-query/package.json index 7474a1f6cf..4fcd4b9449 100644 --- a/packages/svelte-query/package.json +++ b/packages/svelte-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/svelte-query", - "version": "5.29.0", + "version": "5.31.0", "description": "Primitives for managing, caching and syncing asynchronous and remote data in Svelte", "author": "Lachlan Collins", "license": "MIT", diff --git a/packages/vue-query-devtools/package.json b/packages/vue-query-devtools/package.json index cd6e18ab9a..8d458de3ca 100644 --- a/packages/vue-query-devtools/package.json +++ b/packages/vue-query-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-query-devtools", - "version": "5.29.0", + "version": "5.31.0", "description": "Developer tools to interact with and visualize the TanStack/vue-query cache", "author": "tannerlinsley", "license": "MIT", diff --git a/packages/vue-query/package.json b/packages/vue-query/package.json index f45958d1d1..88b7eec735 100644 --- a/packages/vue-query/package.json +++ b/packages/vue-query/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-query", - "version": "5.29.0", + "version": "5.31.0", "description": "Hooks for managing, caching and syncing asynchronous and remote data in Vue", "author": "Damian Osipiuk", "license": "MIT", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e4a1c6ba67..106fdf085c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -155,7 +155,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/common@17.3.3)(@angular/core@17.3.3)(@angular/platform-browser@17.3.3)(rxjs@7.8.1) '@tanstack/angular-query-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-experimental rxjs: specifier: ^7.8.1 @@ -177,7 +177,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/compiler@17.3.3)(typescript@5.2.2) '@tanstack/angular-query-devtools-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-devtools-experimental typescript: specifier: 5.2.2 @@ -210,7 +210,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/common@17.3.3)(@angular/core@17.3.3)(@angular/platform-browser@17.3.3)(rxjs@7.8.1) '@tanstack/angular-query-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-experimental rxjs: specifier: ^7.8.1 @@ -232,7 +232,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/compiler@17.3.3)(typescript@5.2.2) '@tanstack/angular-query-devtools-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-devtools-experimental typescript: specifier: 5.2.2 @@ -265,7 +265,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/common@17.3.3)(@angular/core@17.3.3)(@angular/platform-browser@17.3.3)(rxjs@7.8.1) '@tanstack/angular-query-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-experimental rxjs: specifier: ^7.8.1 @@ -287,7 +287,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/compiler@17.3.3)(typescript@5.2.2) '@tanstack/angular-query-devtools-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-devtools-experimental typescript: specifier: 5.2.2 @@ -320,7 +320,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/common@17.3.3)(@angular/core@17.3.3)(@angular/platform-browser@17.3.3)(rxjs@7.8.1) '@tanstack/angular-query-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-experimental rxjs: specifier: ^7.8.1 @@ -342,7 +342,7 @@ importers: specifier: ^17.3.3 version: 17.3.3(@angular/compiler@17.3.3)(typescript@5.2.2) '@tanstack/angular-query-devtools-experimental': - specifier: ^5.30.0 + specifier: ^5.31.0 version: link:../../../packages/angular-query-devtools-experimental typescript: specifier: 5.2.2 @@ -357,10 +357,10 @@ importers: specifier: 4.22.1 version: 4.22.1 '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools algoliasearch: specifier: 4.22.1 @@ -394,10 +394,10 @@ importers: examples/react/auto-refetching: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -418,10 +418,10 @@ importers: examples/react/basic: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -446,10 +446,10 @@ importers: examples/react/basic-graphql-request: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools graphql: specifier: ^16.8.1 @@ -474,16 +474,16 @@ importers: examples/react/basic-typescript: dependencies: '@tanstack/query-sync-storage-persister': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/query-sync-storage-persister '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools '@tanstack/react-query-persist-client': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-persist-client axios: specifier: ^1.6.7 @@ -523,10 +523,10 @@ importers: examples/react/default-query-function: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -548,10 +548,10 @@ importers: examples/react/infinite-query-with-max-pages: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -575,10 +575,10 @@ importers: examples/react/load-more-infinite-scroll: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -602,10 +602,10 @@ importers: examples/react/nextjs: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools ky: specifier: ^1.2.0 @@ -629,13 +629,13 @@ importers: examples/react/nextjs-suspense-streaming: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools '@tanstack/react-query-next-experimental': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-next-experimental next: specifier: ^14.0.0 @@ -663,19 +663,19 @@ importers: examples/react/offline: dependencies: '@tanstack/query-sync-storage-persister': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/query-sync-storage-persister '@tanstack/react-location': specifier: ^3.7.4 version: 3.7.4(react-dom@18.2.0)(react@18.2.0) '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools '@tanstack/react-query-persist-client': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-persist-client ky: specifier: ^1.2.0 @@ -703,10 +703,10 @@ importers: examples/react/optimistic-updates-cache: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -740,10 +740,10 @@ importers: examples/react/optimistic-updates-ui: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -777,10 +777,10 @@ importers: examples/react/pagination: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -801,10 +801,10 @@ importers: examples/react/playground: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools react: specifier: ^18.2.0 @@ -823,10 +823,10 @@ importers: examples/react/prefetching: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -856,10 +856,10 @@ importers: specifier: ^6.3.16 version: 6.3.16(@react-navigation/native@6.1.6)(react-native-gesture-handler@2.15.0)(react-native-safe-area-context@4.9.0)(react-native-screens@3.29.0)(react-native@0.73.4)(react@18.2.0) '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools expo: specifier: ^50.0.6 @@ -908,10 +908,10 @@ importers: examples/react/react-router: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools localforage: specifier: ^1.10.0 @@ -972,10 +972,10 @@ importers: specifier: ^5.15.2 version: 5.15.2(@types/react@18.2.61)(react@18.2.0) '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools react: specifier: ^18.2.0 @@ -1000,10 +1000,10 @@ importers: examples/react/shadow-dom: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools react: specifier: ^18.2.0 @@ -1046,10 +1046,10 @@ importers: examples/react/simple: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -1083,10 +1083,10 @@ importers: specifier: ^5.15.2 version: 5.15.2(@types/react@18.2.61)(react@18.2.0) '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools react: specifier: ^18.2.0 @@ -1111,10 +1111,10 @@ importers: examples/react/suspense: dependencies: '@tanstack/react-query': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query '@tanstack/react-query-devtools': - specifier: ^5.29.2 + specifier: ^5.31.0 version: link:../../../packages/react-query-devtools axios: specifier: ^1.6.7 @@ -1157,10 +1157,10 @@ importers: specifier: ^7.5.3 version: 7.5.3(astro@4.6.2)(react@18.2.0) '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools astro: specifier: ^4.6.1 @@ -1178,10 +1178,10 @@ importers: examples/solid/basic-graphql-request: dependencies: '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools graphql: specifier: ^16.8.1 @@ -1206,10 +1206,10 @@ importers: examples/solid/basic-typescript: dependencies: '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools solid-js: specifier: ^1.8.14 @@ -1228,10 +1228,10 @@ importers: examples/solid/default-query-function: dependencies: '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools solid-js: specifier: ^1.8.14 @@ -1250,10 +1250,10 @@ importers: examples/solid/simple: dependencies: '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools solid-js: specifier: ^1.8.14 @@ -1284,10 +1284,10 @@ importers: specifier: ^1.0.0-rc.0 version: 1.0.0-rc.0(@testing-library/jest-dom@6.4.2)(rollup@4.14.1)(solid-js@1.8.14)(vinxi@0.3.11)(vite@4.5.1) '@tanstack/solid-query': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query '@tanstack/solid-query-devtools': - specifier: ^5.30.6 + specifier: ^5.31.0 version: link:../../../packages/solid-query-devtools solid-js: specifier: ^1.8.14 @@ -1299,10 +1299,10 @@ importers: examples/svelte/auto-refetching: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1330,10 +1330,10 @@ importers: examples/svelte/basic: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1361,10 +1361,10 @@ importers: examples/svelte/load-more-infinite-scroll: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1392,10 +1392,10 @@ importers: examples/svelte/optimistic-updates-typescript: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1423,10 +1423,10 @@ importers: examples/svelte/playground: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1454,10 +1454,10 @@ importers: examples/svelte/simple: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/vite-plugin-svelte': @@ -1482,10 +1482,10 @@ importers: examples/svelte/ssr: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1513,10 +1513,10 @@ importers: examples/svelte/star-wars: dependencies: '@tanstack/svelte-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query '@tanstack/svelte-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/svelte-query-devtools devDependencies: '@sveltejs/adapter-auto': @@ -1553,10 +1553,10 @@ importers: examples/vue/basic: dependencies: '@tanstack/vue-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query '@tanstack/vue-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query-devtools vue: specifier: ^3.3.0 @@ -1575,7 +1575,7 @@ importers: examples/vue/dependent-queries: dependencies: '@tanstack/vue-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query vue: specifier: ^3.3.0 @@ -1594,16 +1594,16 @@ importers: examples/vue/persister: dependencies: '@tanstack/query-core': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/query-core '@tanstack/query-persist-client-core': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/query-persist-client-core '@tanstack/query-sync-storage-persister': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/query-sync-storage-persister '@tanstack/vue-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query idb-keyval: specifier: ^6.2.1 @@ -1625,10 +1625,10 @@ importers: examples/vue/simple: dependencies: '@tanstack/vue-query': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query '@tanstack/vue-query-devtools': - specifier: ^5.29.0 + specifier: ^5.31.0 version: link:../../../packages/vue-query-devtools vue: specifier: ^3.3.0