From dbb5ad87ed66f6eb558d0f17239f3572d3f622e1 Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Thu, 22 Dec 2022 22:26:01 +0100 Subject: [PATCH 1/7] docs: vue guides --- docs/config.json | 141 ++++++++++++++++++ docs/react/graphql.md | 16 +- .../guides/background-fetching-indicators.md | 21 ++- docs/react/guides/default-query-function.md | 12 +- docs/react/guides/dependent-queries.md | 10 +- docs/react/overview.md | 23 ++- docs/react/quick-start.md | 9 +- docs/react/typescript.md | 43 ++++-- docs/vue/devtools.md | 13 ++ docs/vue/graphql.md | 9 ++ .../guides/background-fetching-indicators.md | 46 ++++++ docs/vue/guides/caching.md | 6 + docs/vue/guides/custom-client.md | 63 ++++++++ docs/vue/guides/custom-logger.md | 6 + docs/vue/guides/default-query-function.md | 33 ++++ docs/vue/guides/dependent-queries.md | 28 ++++ docs/vue/installation.md | 17 +-- docs/vue/overview.md | 13 +- docs/vue/quick-start.md | 28 ++-- docs/vue/typescript.md | 38 +++++ 20 files changed, 508 insertions(+), 67 deletions(-) create mode 100644 docs/vue/devtools.md create mode 100644 docs/vue/graphql.md create mode 100644 docs/vue/guides/background-fetching-indicators.md create mode 100644 docs/vue/guides/caching.md create mode 100644 docs/vue/guides/custom-client.md create mode 100644 docs/vue/guides/custom-logger.md create mode 100644 docs/vue/guides/default-query-function.md create mode 100644 docs/vue/guides/dependent-queries.md create mode 100644 docs/vue/typescript.md diff --git a/docs/config.json b/docs/config.json index 0bee2e6155..50211fd0a8 100644 --- a/docs/config.json +++ b/docs/config.json @@ -432,6 +432,147 @@ { "label": "Quick Start", "to": "vue/quick-start" + }, + { + "label": "Devtools", + "to": "vue/devtools" + }, + { + "label": "TypeScript", + "to": "vue/typescript" + }, + { + "label": "GraphQL", + "to": "vue/graphql" + } + ] + }, + { + "label": "Guides & Concepts", + "children": [ + { + "label": "Important Defaults", + "to": "vue/guides/important-defaults" + }, + { + "label": "Queries", + "to": "vue/guides/queries" + }, + { + "label": "Query Keys", + "to": "vue/guides/query-keys" + }, + { + "label": "Query Functions", + "to": "vue/guides/query-functions" + }, + { + "label": "Network Mode", + "to": "vue/guides/network-mode" + }, + { + "label": "Parallel Queries", + "to": "vue/guides/parallel-queries" + }, + { + "label": "Dependent Queries", + "to": "vue/guides/dependent-queries" + }, + { + "label": "Background Fetching Indicators", + "to": "vue/guides/background-fetching-indicators" + }, + { + "label": "Window Focus Refetching", + "to": "vue/guides/window-focus-refetching" + }, + { + "label": "Disabling/Pausing Queries", + "to": "vue/guides/disabling-queries" + }, + { + "label": "Query Retries", + "to": "vue/guides/query-retries" + }, + { + "label": "Paginated Queries", + "to": "vue/guides/paginated-queries" + }, + { + "label": "Infinite Queries", + "to": "vue/guides/infinite-queries" + }, + { + "label": "Initial Query Data", + "to": "vue/guides/initial-query-data" + }, + { + "label": "Placeholder Query Data", + "to": "vue/guides/placeholder-query-data" + }, + { + "label": "Prefetching", + "to": "vue/guides/prefetching" + }, + { + "label": "Mutations", + "to": "vue/guides/mutations" + }, + { + "label": "Query Invalidation", + "to": "vue/guides/query-invalidation" + }, + { + "label": "Invalidation from Mutations", + "to": "vue/guides/invalidations-from-mutations" + }, + { + "label": "Updates from Mutation Responses", + "to": "vue/guides/updates-from-mutation-responses" + }, + { + "label": "Optimistic Updates", + "to": "vue/guides/optimistic-updates" + }, + { + "label": "Query Cancellation", + "to": "vue/guides/query-cancellation" + }, + { + "label": "Scroll Restoration", + "to": "vue/guides/scroll-restoration" + }, + { + "label": "Filters", + "to": "vue/guides/filters" + }, + { + "label": "SSR & Next.js", + "to": "vue/guides/ssr" + }, + { + "label": "Caching", + "to": "vue/guides/caching" + }, + { + "label": "Default Query Fn", + "to": "vue/guides/default-query-function" + }, + { + "label": "Suspense", + "to": "vue/guides/suspense" + }, + { + "label": "Custom Logger", + "to": "vue/guides/custom-logger" + }, + { + "label": "Testing", + "to": "vue/guides/testing" + }, + { + "label": "Does this replace [Redux, MobX, etc]?", + "to": "vue/guides/does-this-replace-client-state" } ] } diff --git a/docs/react/graphql.md b/docs/react/graphql.md index c3c9905330..8d02dda018 100644 --- a/docs/react/graphql.md +++ b/docs/react/graphql.md @@ -7,16 +7,17 @@ Because React Query's fetching mechanisms are agnostically built on Promises, yo > Keep in mind that React Query does not support normalized caching. While a vast majority of users do not actually need a normalized cache or even benefit from it as much as they believe they do, there may be very rare circumstances that may warrant it so be sure to check with us first to make sure it's truly something you need! -## Type-Safety and Code Generation +[//]: # 'Codegen' +## Type-Safety and Code Generation React Query, used in combination with `graphql-request^5` and [GraphQL Code Generator](https://graphql-code-generator.com/) provides full-typed GraphQL operations: ```tsx -import request from 'graphql-request'; -import { useQuery } from '@tanstack/react-query'; +import request from 'graphql-request' +import { useQuery } from '@tanstack/react-query' -import { graphql } from './gql/gql'; +import { graphql } from './gql/gql' const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` query allFilmsWithVariablesQuery($first: Int!) { @@ -29,7 +30,7 @@ const allFilmsWithVariablesQueryDocument = graphql(/* GraphQL */ ` } } } -`); +`) function App() { // `data` is fully typed! @@ -40,13 +41,14 @@ function App() { 'https://swapi-graphql.netlify.app/.netlify/functions/index', allFilmsWithVariablesQueryDocument, // variables are type-checked too! - {first: 10} + { first: 10 }, ), }) // ... } ``` -_You can find a [complete example in the repo](https://github.com/dotansimha/graphql-code-generator/tree/7c25c4eeb77f88677fd79da557b7b5326e3f3950/examples/front-end/react/tanstack-react-query)_ +_You can find a [complete example in the repo](https://github.com/dotansimha/graphql-code-generator/tree/7c25c4eeb77f88677fd79da557b7b5326e3f3950/examples/front-end/react/tanstack-react-query)_ Get started with the [dedicated guide on GraphQL Code Generator documentation](https://www.the-guild.dev/graphql/codegen/docs/guides/react-vue). +[//]: # (Codegen) diff --git a/docs/react/guides/background-fetching-indicators.md b/docs/react/guides/background-fetching-indicators.md index 75dfffa126..c8a76605d6 100644 --- a/docs/react/guides/background-fetching-indicators.md +++ b/docs/react/guides/background-fetching-indicators.md @@ -5,11 +5,18 @@ title: Background Fetching Indicators A query's `status === 'loading'` state is sufficient enough to show the initial hard-loading state for a query, but sometimes you may want to display an additional indicator that a query is refetching in the background. To do this, queries also supply you with an `isFetching` boolean that you can use to show that it's in a fetching state, regardless of the state of the `status` variable: +[//]: # 'Example' + ```tsx function Todos() { - const { status, data: todos, error, isFetching } = useQuery({ - queryKey: ['todos'], - queryFn: fetchTodos, + const { + status, + data: todos, + error, + isFetching, + } = useQuery({ + queryKey: ['todos'], + queryFn: fetchTodos, }) return status === 'loading' ? ( @@ -21,7 +28,7 @@ function Todos() { {isFetching ?
Refreshing...
: null}
- {todos.map(todo => ( + {todos.map((todo) => ( ))}
@@ -30,10 +37,14 @@ function Todos() { } ``` +[//]: # 'Example' + ## Displaying Global Background Fetching Loading State In addition to individual query loading states, if you would like to show a global loading indicator when **any** queries are fetching (including in the background), you can use the `useIsFetching` hook: +[//]: # 'Example2' + ```tsx import { useIsFetching } from '@tanstack/react-query' @@ -45,3 +56,5 @@ function GlobalLoadingIndicator() { ) : null } ``` + +[//]: # 'Example2' diff --git a/docs/react/guides/default-query-function.md b/docs/react/guides/default-query-function.md index e9baf3d9f6..47c3e9e0e0 100644 --- a/docs/react/guides/default-query-function.md +++ b/docs/react/guides/default-query-function.md @@ -5,12 +5,16 @@ title: Default Query Function If you find yourself wishing for whatever reason that you could just share the same query function for your entire app and just use query keys to identify what it should fetch, you can do that by providing a **default query function** to React Query: +[//]: # 'Example' + ```tsx // Define a default query function that will receive the query key const defaultQueryFn = async ({ queryKey }) => { - const { data } = await axios.get(`https://jsonplaceholder.typicode.com${queryKey[0]}`); - return data; -}; + const { data } = await axios.get( + `https://jsonplaceholder.typicode.com${queryKey[0]}`, + ) + return data +} // provide the default query function to your app with defaultOptions const queryClient = new QueryClient({ @@ -47,4 +51,6 @@ function Post({ postId }) { } ``` +[//]: # 'Example' + If you ever want to override the default queryFn, you can just provide your own like you normally would. diff --git a/docs/react/guides/dependent-queries.md b/docs/react/guides/dependent-queries.md index 18f6d6ae44..79312b225b 100644 --- a/docs/react/guides/dependent-queries.md +++ b/docs/react/guides/dependent-queries.md @@ -5,6 +5,8 @@ title: Dependent Queries Dependent (or serial) queries depend on previous ones to finish before they can execute. To achieve this, it's as easy as using the `enabled` option to tell a query when it is ready to run: +[//]: # 'Example' + ```tsx // Get the user const { data: user } = useQuery({ @@ -15,7 +17,11 @@ const { data: user } = useQuery({ const userId = user?.id // Then get the user's projects -const { status, fetchStatus, data: projects } = useQuery({ +const { + status, + fetchStatus, + data: projects, +} = useQuery({ queryKey: ['projects', userId], queryFn: getProjectsByUser, // The query will not execute until the userId exists @@ -23,6 +29,8 @@ const { status, fetchStatus, data: projects } = useQuery({ }) ``` +[//]: # 'Example' + The `projects` query will start in: ```tsx diff --git a/docs/react/overview.md b/docs/react/overview.md index e022816bd1..d3aaaee0e3 100644 --- a/docs/react/overview.md +++ b/docs/react/overview.md @@ -40,7 +40,8 @@ On a more technical note, React Query will likely: - Have a direct impact on your end-users by making your application feel faster and more responsive than ever before. - Potentially help you save on bandwidth and increase memory performance -[//]: # (Example) +[//]: # 'Example' + ## Enough talk, show me some code already! In the example below, you can see React Query in its most basic and simple form being used to fetch the GitHub stats for the React Query GitHub project itself: @@ -48,7 +49,11 @@ In the example below, you can see React Query in its most basic and simple form [Open in CodeSandbox](https://codesandbox.io/s/github/tannerlinsley/react-query/tree/main/examples/react/simple) ```tsx -import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query' +import { + QueryClient, + QueryClientProvider, + useQuery, +} from '@tanstack/react-query' const queryClient = new QueryClient() @@ -64,9 +69,9 @@ function Example() { const { isLoading, error, data } = useQuery({ queryKey: ['repoData'], queryFn: () => - fetch('https://api.github.com/repos/tanstack/query').then(res => - res.json() - ) + fetch('https://api.github.com/repos/tannerlinsley/react-query').then( + (res) => res.json(), + ), }) if (isLoading) return 'Loading...' @@ -84,11 +89,13 @@ function Example() { ) } ``` -[//]: # (Example) + +[//]: # 'Example' ## You talked me into it, so what now? -[//]: # (Course) +[//]: # 'Course' + - Consider taking the official [React Query Course](https://ui.dev/react-query?from=tanstack) (or buying it for your whole team!) -[//]: # (Course) + [//]: # (Course) - Learn React Query at your own pace with our amazingly thorough [Walkthrough Guide](../installation) and [API Reference](../reference/useQuery) diff --git a/docs/react/quick-start.md b/docs/react/quick-start.md index 9f6003de4b..58eb15900c 100644 --- a/docs/react/quick-start.md +++ b/docs/react/quick-start.md @@ -9,9 +9,9 @@ This code snippet very briefly illustrates the 3 core concepts of React Query: - [Mutations](./guides/mutations) - [Query Invalidation](./guides/query-invalidation) -[//]: # (Example) -If you're looking for a fully functioning example, please have a look at our [simple codesandbox example](../examples/react/simple) +[//]: # 'Example' +If you're looking for a fully functioning example, please have a look at our [simple codesandbox example](../examples/react/simple) ```tsx import { @@ -54,7 +54,7 @@ function Todos() { return (
@@ -75,6 +75,7 @@ function Todos() { render(, document.getElementById('root')) ``` -[//]: # (Example) + +[//]: # 'Example' These three concepts make up most of the core functionality of React Query. The next sections of the documentation will go over each of these core concepts in great detail. diff --git a/docs/react/typescript.md b/docs/react/typescript.md index 6b67741cd8..5800ec614f 100644 --- a/docs/react/typescript.md +++ b/docs/react/typescript.md @@ -18,36 +18,49 @@ Types in React Query generally flow through very well so that you don't have to ```ts const { data } = useQuery({ -// ^? const data: number | undefined + // ^? const data: number | undefined queryKey: ['test'], - queryFn: () => Promise.resolve(5) + queryFn: () => Promise.resolve(5), }) ``` +[//]: # 'Playground1' + [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFC8MQAdqnhIAJnRh0icALwoM2XHgAUAbSqDkIAEa4qAXQA0cFQEo5APjgAFciGAYAdLVQQANgDd0KgKxmzXgB6ILgw8IA9AH5eIA) +[//]: # 'Playground1' + ```ts const { data } = useQuery({ -// ^? const data: string | undefined + // ^? const data: string | undefined queryKey: ['test'], queryFn: () => Promise.resolve(5), - select: data => data.toString(), + select: (data) => data.toString(), }) ``` +[//]: # 'Playground2' + [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFC8MQAdqnhIAJnRh0icALwoM2XHgAUAbSox0IqgF0ANHBUBKOQD44ABXIhgGAHS1UEADYA3dCoCsxw0gwu6EwAXHASUuZhknT2MBAAyjBQwIIA5iaExrwA9Nlw+QUAegD8vEA) +[//]: # 'Playground2' + This works best if your `queryFn` has a well-defined returned type. Keep in mind that most data fetching libraries return `any` per default, so make sure to extract it to a properly typed function: ```ts -const fetchGroups = (): Promise => axios.get('/groups').then(response => response.data) +const fetchGroups = (): Promise => + axios.get('/groups').then((response) => response.data) const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups }) // ^? const data: Group[] | undefined - ``` +``` + +[//]: # 'Playground3' [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFCiSw4dAB7AIqUuUpURY1Nx68YeMOjgBxcsjBwAvIjjAAJgC44AO2QgARriK9eDCOdTwS6GAwAWmiNon6ABQAlGYAClLAGAA8vtoA2gC6AHx6qbLiAHQA5h6BVAD02Vpg8sGZMF7o5oG0qJAuarqpdQ0YmUZ0MHTBDjxOLvBInd1EeigY2Lh4gfFUxX6lVIkANKQe3nGlvTwFBXAHhwB6APxwA65wI3RmW0lwAD4o5kboJMDm6Ea8QA) +[//]: # 'Playground3' + ## Type Narrowing React Query uses a [discriminated union type](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions) for the query result, discriminated by the `status` field and the derived status boolean flags. This will allow you to check for e.g. `success` status to make `data` defined: @@ -59,13 +72,17 @@ const { data, isSuccess } = useQuery({ }) if (isSuccess) { - data -// ^? const data: number + data + // ^? const data: number } ``` +[//]: # 'Playground4' + [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFC8MQAdqnhIAJnRh0ANHGCoAysgYN0qVETgBeFBmy48ACgDaVGGphUAurMMBKbQD44ABXIh56AHS1UEADYAbuiGAKx2dry8wCRwhvJKKmqoDgi8cBlwElK8APS5GQB6APy8hLxAA) +[//]: # 'Playground4' + ## Typing the error field The type for error defaults to `unknown`. This is in line with what TypeScript gives you per default in a catch clauses (see [useUnknownInCatchVariables](https://devblogs.microsoft.com/typescript/announcing-typescript-4-4/#use-unknown-catch-variables)). The safest way to work with `error` would be to perform a runtime check; another way would be to explicitly define types for `data` and `error`: @@ -76,19 +93,27 @@ const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups }) if (error instanceof Error) { error -// ^? const error: Error + // ^? const error: Error } ``` +[//]: # 'Playground5' + [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFCiSw4dAB7AIqUuUpURY1Nx68YeMOjgBxcsjBwAvIjjAAJgC44AO2QgARriK9eDCOdTwS6GAwAWmiNon6ABQAlGYAClLAGAA8vtoA2gC6AHx6qbLiAHQA5h6BVAD02Vpg8sGZMF7o5oG0qJAuarqpdQ0YmUZ0MHTBDjxOLvBIuORQRHooGNi4eIHxVMV+pVSJADSkHt5xpb08BQVwh0cAegD8fcAkcIEj0IaDdOYM6BBXAKJQo8GIvIe3ULx9nAzrxCEA) +[//]: # 'Playground5' + ```ts const { error } = useQuery(['groups'], fetchGroups) // ^? const error: Error | null ``` +[//]: # 'Playground6' + [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFCiSw4dAB7AIqUuUpURY1Nx68YeMOjgBxcsjBwAvIjjAAJgC44AO2QgARriK9eDCOdTwS6GAwAWmiNon6ABQAlGYAClLAGAA8vtoA2gC6AHx6qbLiAHQA5h6BVAD02Vpg8sGZMF7o5oG0qJAuarqpdQ0YmUZ0MHTBDjxOLvBIuORQRHooGNi4eLElSQA0cACiUKPJgfFUxX6lVIlL7p4+Jai9PAUFcNc3AHoA-LxAA) +[//]: # 'Playground6' + ## Further Reading For tips and tricks around type inference, have a look at [React Query and TypeScript](../community/tkdodos-blog#6-react-query-and-typescript) from diff --git a/docs/vue/devtools.md b/docs/vue/devtools.md new file mode 100644 index 0000000000..44b6d09f05 --- /dev/null +++ b/docs/vue/devtools.md @@ -0,0 +1,13 @@ +--- +id: devtools +title: Devtools +--- + +Wave your hands in the air and shout hooray because Vue Query comes with dedicated devtools! 🥳 + +When you begin your Vue Query journey, you'll want these devtools by your side. They help visualize all of the inner workings of Vue Query and will likely save you hours of debugging if you find yourself in a pinch! + +The only thing you need to do is to install official **[Vue Devtools](https://devtools.vuejs.org/guide/installation.html)** + +Vue Query will seemingly integrate with official devtools, adding custom inspector and timeline events. +Devtools would be treeshaken from production bundles by default. diff --git a/docs/vue/graphql.md b/docs/vue/graphql.md new file mode 100644 index 0000000000..dfd2c02a42 --- /dev/null +++ b/docs/vue/graphql.md @@ -0,0 +1,9 @@ +--- +id: graphql +title: GraphQL +ref: docs/react/graphql.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- + +[//]: # 'Codegen' +[//]: # 'Codegen' diff --git a/docs/vue/guides/background-fetching-indicators.md b/docs/vue/guides/background-fetching-indicators.md new file mode 100644 index 0000000000..22b96f8902 --- /dev/null +++ b/docs/vue/guides/background-fetching-indicators.md @@ -0,0 +1,46 @@ +--- +id: background-fetching-indicators +title: Background Fetching Indicators +ref: docs/react/guides/background-fetching-indicators.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- + +[//]: # 'Example' + +```vue + + + +``` + +[//]: # 'Example' +[//]: # 'Example2' + +```vue + + + +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/caching.md b/docs/vue/guides/caching.md new file mode 100644 index 0000000000..bfb8628f43 --- /dev/null +++ b/docs/vue/guides/caching.md @@ -0,0 +1,6 @@ +--- +id: caching +title: Caching Examples +ref: docs/react/guides/caching.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- diff --git a/docs/vue/guides/custom-client.md b/docs/vue/guides/custom-client.md new file mode 100644 index 0000000000..ef1839c5f0 --- /dev/null +++ b/docs/vue/guides/custom-client.md @@ -0,0 +1,63 @@ +### Custom client + +Vue Query allows providing custom `QueryClient` for Vue context. + +It might be handy when you need to create `QueryClient` beforehand to integrate it with other libraries that do not have access to the Vue context. + +For this reason, `VueQueryPlugin` accepts either `QueryClientConfig` or `QueryClient` as a plugin options. + +If You provide `QueryClientConfig`, `QueryClient` instance will be created internally and provided to Vue context. + +```ts +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClientConfig: { + defaultOptions: { queries: { staleTime: 3600 } }, + }, +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +```ts +const myClient = new QueryClient(queryClientConfig) +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClient: myClient, +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +### Custom context key + +You can also customize the key under which `QueryClient` will be accessible in Vue context. This can be usefull is you want to avoid name clashing between multiple apps on the same page with Vue2. + +It works both with default, and custom `QueryClient` + +```ts +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClientKey: 'Foo', +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +```ts +const myClient = new QueryClient(queryClientConfig) +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClient: myClient, + queryClientKey: 'Foo', +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +To use the custom client key, You have to provide it as a query options + +```js +useQuery('query1', fetcher, { queryClientKey: 'foo' }) +``` + +Internally custom key will be combined with default query key as a suffix. But user do not have to worry about it. + +```ts +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClientKey: 'Foo', +} +app.use(VueQueryPlugin, vueQueryPluginOptions) // -> VUE_QUERY_CLIENT:Foo +``` diff --git a/docs/vue/guides/custom-logger.md b/docs/vue/guides/custom-logger.md new file mode 100644 index 0000000000..bcbf58ebfc --- /dev/null +++ b/docs/vue/guides/custom-logger.md @@ -0,0 +1,6 @@ +--- +id: custom-logger +title: Custom Logger +ref: docs/react/guides/custom-logger.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- diff --git a/docs/vue/guides/default-query-function.md b/docs/vue/guides/default-query-function.md new file mode 100644 index 0000000000..d400bfa802 --- /dev/null +++ b/docs/vue/guides/default-query-function.md @@ -0,0 +1,33 @@ +--- +id: default-query-function +title: Default Query Function +ref: docs/react/guides/default-query-function.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- + +[//]: # 'Example' + +```tsx +// Define a default query function that will receive the query key +const defaultQueryFn = async ({ queryKey }) => { + const { data } = await axios.get( + `https://jsonplaceholder.typicode.com${queryKey[0]}`, + ) + return data +} + +// provide the default query function to your app with defaultOptions +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClientConfig: { + defaultOptions: { queries: { queryFn: defaultQueryFn } }, + }, +} +app.use(VueQueryPlugin, vueQueryPluginOptions) + +// All you have to do now is pass a key! +const { status, data, error, isFetching } = useQuery({ + queryKey: [`/posts/${postId}`], +}) +``` + +[//]: # 'Example' diff --git a/docs/vue/guides/dependent-queries.md b/docs/vue/guides/dependent-queries.md new file mode 100644 index 0000000000..d957d7b729 --- /dev/null +++ b/docs/vue/guides/dependent-queries.md @@ -0,0 +1,28 @@ +--- +id: dependent-queries +title: Dependent Queries +ref: docs/react/guides/dependent-queries.md +replace: { 'React': 'Vue', 'react-query': 'vue-query' } +--- + +[//]: # 'Example' + +```js +// Get the user +const { data: user } = useQuery({ + queryKey: ['user', email], + queryFn: () => getUserByEmail(email.value), +}) + +const userId = computed(() => user.value?.id) +const enabled = computed(() => !!user.value?.id) + +// Then get the user's projects +const { isIdle, data: projects } = useQuery({ + queryKey: ['projects', userId], + queryFn: () => getProjectsByUser(userId.value), + enabled, // The query will not execute until `enabled == true` +}) +``` + +[//]: # 'Example' diff --git a/docs/vue/installation.md b/docs/vue/installation.md index 28ab738307..bdbabca3aa 100644 --- a/docs/vue/installation.md +++ b/docs/vue/installation.md @@ -28,7 +28,7 @@ Before using Vue Query, you need to initialize it using `VueQueryPlugin` ```ts import { VueQueryPlugin } from "@tanstack/vue-query"; -app.use(VueQueryPlugin); +app.use(VueQueryPlugin) ``` ### Use of Composition API with ` diff --git a/docs/vue/overview.md b/docs/vue/overview.md index d772c39ca6..0e9bde76de 100644 --- a/docs/vue/overview.md +++ b/docs/vue/overview.md @@ -2,13 +2,10 @@ id: overview title: Overview ref: docs/react/overview.md -replace: { - 'React': 'Vue', -} +replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- -[//]: # (Example) -[//]: # (Example) - -[//]: # (Course) -[//]: # (Course) \ No newline at end of file +[//]: # 'Example' +[//]: # 'Example' +[//]: # 'Course' +[//]: # 'Course' diff --git a/docs/vue/quick-start.md b/docs/vue/quick-start.md index eed57c7ca8..10b15d16b2 100644 --- a/docs/vue/quick-start.md +++ b/docs/vue/quick-start.md @@ -2,37 +2,40 @@ id: quick-start title: Quick Start ref: docs/react/quick-start.md -replace: { - 'React': 'Vue', -} +replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- -[//]: # (Example) +[//]: # 'Example' + If you're looking for a fully functioning example, please have a look at our [basic codesandbox example](../examples/vue/basic) + ```vue @@ -46,4 +49,5 @@ function onButtonClick() { ``` -[//]: # (Example) + +[//]: # 'Example' diff --git a/docs/vue/typescript.md b/docs/vue/typescript.md new file mode 100644 index 0000000000..70e598b599 --- /dev/null +++ b/docs/vue/typescript.md @@ -0,0 +1,38 @@ +--- +id: typescript +title: TypeScript +ref: docs/react/typescript.md +replace: + { 'React': 'Vue', 'react-query package version': 'vue-query package version' } +--- + +[//]: # 'Playground1' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUBNYRm8JABN6DInAC8KDNlx4AFAG0qjZCABGuKgF0ANHB0BKNQD44ABXIhgGAHRR0qCAA23Og6AKx2dhKcnHCxcQB6APwSQA) + +[//]: # 'Playground1' +[//]: # 'Playground2' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUBNYRm8JABN6DInAC8KDNlx4AFAG0qMdCyoBdADRwdASjUA+OAAVyIYBgB0UYxAA23dDoArNaWSBg+6KwwAFxwisqqDvH07jAQAMowUMCMAOY2hNYSnJxwZeUAegD8EkA) + +[//]: # 'Playground2' +[//]: # 'Playground3' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUKEiw49AB7AIqUuUpV5i1GPESYeMOjgBxcsjBwAvIjjAAJgC44jZCABGuIhImsIzeCXQYVgALEwgzZSsACgBKRwAFVWAMAB4wswBtAF0APks8jSUAOgBzQKiqThLTMC0Yophg9EYoqHRUSGZDCzy2jt8MItt6BhivcR8-a2GGIksUDGxcPCiMqmrw2qosgBpSQJD02rHxTk44C8uAPQB+CSA) + +[//]: # 'Playground3' +[//]: # 'Playground4' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUKEixEcKOnqsYwbuiKlylKr3RUA3BImsIzeEgAm9BgBo4wVAGVkrVulSp1AXjkKlK9AAUaFjCeAEA2lQwbjBUALq2AQCUcJ4AfHAACpr26AB08qgQADaqAQCsSVWGkiRwAfZOLm6oKQgScJ1wlgwSnJydAHoA-BKEEkA) + +[//]: # 'Playground4' +[//]: # 'Playground5' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUKEiw49AB7AIqUuUpV5i1GPESYeMOjgBxcsjBwAvIjjAAJgC44jZCABGuIhImsIzeCXQYVgALEwgzZSsACgBKRwAFVWAMAB4wswBtAF0APks8jSUAOgBzQKiqThLTMC0Yophg9EYoqHRUSGZDCzy2jt8MItt6BhivcR8-a1xyKCJLFAxsXDwojKpq8NqqLIAaUkCQ9Nqx8U5OOEurgD0AfnHgEjgomegbPyZWdAgngFEoWYxRASS6vKASc5wO4SQhAA) + +[//]: # 'Playground5' +[//]: # 'Playground6' + +[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUKEiw49AB7AIqUuUpV5i1GPESYeMOjgBxcsjBwAvIjjAAJgC44jZCABGuIhImsIzeCXQYVgALEwgzZSsACgBKRwAFVWAMAB4wswBtAF0APks8jSUAOgBzQKiqThLTMC0Yophg9EYoqHRUSGZDCzy2jt8MItt6BhivcR8-a1xyKCJLFAxsXDw0muyAGjgAUShZnKiMqmrw2qosrYCg0JrUMfFOTjhnl4A9AH4JIA) + +[//]: # 'Playground6' From 752cd519b835858862586ce91ddef6ca9c2b0444 Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Fri, 23 Dec 2022 00:50:13 +0100 Subject: [PATCH 2/7] docs: vue query docs part 2 --- docs/config.json | 4 +- .../community/liaoliao666-react-query-kit.md | 2 +- .../lukemorales-query-key-factory.md | 4 +- docs/react/eslint/exhaustive-deps.md | 4 +- .../eslint/prefer-query-object-syntax.md | 2 +- docs/react/guides/custom-logger.md | 2 +- docs/react/guides/default-query-function.md | 2 +- docs/react/guides/disabling-queries.md | 44 ++--- .../guides/does-this-replace-client-state.md | 16 +- docs/react/guides/filters.md | 2 +- docs/react/guides/important-defaults.md | 8 +- docs/react/guides/infinite-queries.md | 49 ++++- docs/react/guides/initial-query-data.md | 185 ++++++++++-------- .../guides/invalidations-from-mutations.md | 12 +- docs/react/guides/mutations.md | 105 +++++++--- docs/react/guides/testing.md | 12 +- docs/react/plugins/broadcastQueryClient.md | 8 +- .../plugins/createAsyncStoragePersister.md | 4 +- .../plugins/createSyncStoragePersister.md | 6 +- docs/react/plugins/persistQueryClient.md | 22 +-- docs/react/react-native.md | 6 +- docs/react/typescript.md | 12 +- .../guides/background-fetching-indicators.md | 1 - docs/vue/guides/caching.md | 1 - docs/vue/guides/custom-client.md | 15 +- docs/vue/guides/custom-logger.md | 1 - docs/vue/guides/default-query-function.md | 1 - docs/vue/guides/dependent-queries.md | 1 - docs/vue/guides/disabling-queries.md | 56 ++++++ .../guides/does-this-replace-client-state.md | 59 ++++++ docs/vue/guides/filters.md | 5 + docs/vue/guides/important-defaults.md | 8 + docs/vue/guides/infinite-queries.md | 88 +++++++++ docs/vue/guides/initial-query-data.md | 5 + .../guides/invalidations-from-mutations.md | 24 +++ docs/vue/guides/mutations.md | 5 + docs/vue/installation.md | 2 +- packages/vue-query/README.md | 6 +- 38 files changed, 580 insertions(+), 209 deletions(-) create mode 100644 docs/vue/guides/disabling-queries.md create mode 100644 docs/vue/guides/does-this-replace-client-state.md create mode 100644 docs/vue/guides/filters.md create mode 100644 docs/vue/guides/important-defaults.md create mode 100644 docs/vue/guides/infinite-queries.md create mode 100644 docs/vue/guides/initial-query-data.md create mode 100644 docs/vue/guides/invalidations-from-mutations.md create mode 100644 docs/vue/guides/mutations.md diff --git a/docs/config.json b/docs/config.json index 50211fd0a8..bfa23e981c 100644 --- a/docs/config.json +++ b/docs/config.json @@ -527,7 +527,7 @@ "to": "vue/guides/invalidations-from-mutations" }, { - "label": "Updates from Mutation Responses", + "label": "Updates from Mutation", "to": "vue/guides/updates-from-mutation-responses" }, { @@ -571,7 +571,7 @@ "to": "vue/guides/testing" }, { - "label": "Does this replace [Redux, MobX, etc]?", + "label": "Does this replace [Vuex, Pinia]?", "to": "vue/guides/does-this-replace-client-state" } ] diff --git a/docs/react/community/liaoliao666-react-query-kit.md b/docs/react/community/liaoliao666-react-query-kit.md index 4a8a89d070..3e5ee6ab3e 100644 --- a/docs/react/community/liaoliao666-react-query-kit.md +++ b/docs/react/community/liaoliao666-react-query-kit.md @@ -30,7 +30,7 @@ $ yarn add react-query-kit [CodeSandbox](https://codesandbox.io/s/example-react-query-kit-nextjs-uldl88) -```ts +```tsx import { QueryClient, dehydrate } from '@tanstack/react-query' import { createQuery } from 'react-query-kit' diff --git a/docs/react/community/lukemorales-query-key-factory.md b/docs/react/community/lukemorales-query-key-factory.md index 81b02d654a..3ad14a4eca 100644 --- a/docs/react/community/lukemorales-query-key-factory.md +++ b/docs/react/community/lukemorales-query-key-factory.md @@ -22,7 +22,7 @@ $ yarn add @lukemorales/query-key-factory Start by defining the query keys for your app: ### Declare everything in a single file -```ts +```tsx import { createQueryKeyStore } from '@lukemorales/query-key-factory' export const queryKeys = createQueryKeyStore({ @@ -36,7 +36,7 @@ export const queryKeys = createQueryKeyStore({ ``` ### Fine-grained declaration by features -```ts +```tsx import { createQueryKeys, mergeQueryKeys } from '@lukemorales/query-key-factory' // my-api/users.ts diff --git a/docs/react/eslint/exhaustive-deps.md b/docs/react/eslint/exhaustive-deps.md index e3719818bc..c56f398008 100644 --- a/docs/react/eslint/exhaustive-deps.md +++ b/docs/react/eslint/exhaustive-deps.md @@ -10,7 +10,7 @@ This makes sure that queries are cached independently and that queries are refet Examples of **incorrect** code for this rule: -```ts +```tsx /* eslint "@tanstack/query/exhaustive-deps": "error" */ useQuery({ @@ -26,7 +26,7 @@ const todoQueries = { Examples of **correct** code for this rule: -```ts +```tsx useQuery({ queryKey: ["todo", todoId], queryFn: () => api.getTodo(todoId) diff --git a/docs/react/eslint/prefer-query-object-syntax.md b/docs/react/eslint/prefer-query-object-syntax.md index 3d55133c4f..8a53cdbb0a 100644 --- a/docs/react/eslint/prefer-query-object-syntax.md +++ b/docs/react/eslint/prefer-query-object-syntax.md @@ -7,7 +7,7 @@ You can use [`useQuery`](https://tanstack.com/query/v4/docs/reference/useQuery) Standard -```ts +```tsx useQuery(queryKey, queryFn?, options?) // or diff --git a/docs/react/guides/custom-logger.md b/docs/react/guides/custom-logger.md index 8cc9dd330e..a4c075520b 100644 --- a/docs/react/guides/custom-logger.md +++ b/docs/react/guides/custom-logger.md @@ -3,7 +3,7 @@ id: custom-logger title: Custom Logger --- -If you want to change how information is logged by React Query, you can set a custom logger when creating a `QueryClient`. +If you want to change how information is logged by Tanstack Query, you can set a custom logger when creating a `QueryClient`. ```tsx const queryClient = new QueryClient({ diff --git a/docs/react/guides/default-query-function.md b/docs/react/guides/default-query-function.md index 47c3e9e0e0..78ee0eb2b8 100644 --- a/docs/react/guides/default-query-function.md +++ b/docs/react/guides/default-query-function.md @@ -3,7 +3,7 @@ id: default-query-function title: Default Query Function --- -If you find yourself wishing for whatever reason that you could just share the same query function for your entire app and just use query keys to identify what it should fetch, you can do that by providing a **default query function** to React Query: +If you find yourself wishing for whatever reason that you could just share the same query function for your entire app and just use query keys to identify what it should fetch, you can do that by providing a **default query function** to Tanstack Query: [//]: # 'Example' diff --git a/docs/react/guides/disabling-queries.md b/docs/react/guides/disabling-queries.md index 529c869374..2ec1e04755 100644 --- a/docs/react/guides/disabling-queries.md +++ b/docs/react/guides/disabling-queries.md @@ -14,20 +14,16 @@ When `enabled` is `false`: - The query will ignore query client `invalidateQueries` and `refetchQueries` calls that would normally result in the query refetching. - `refetch` returned from `useQuery` can be used to manually trigger the query to fetch. +[//]: # 'Example' + ```tsx function Todos() { - const { - isInitialLoading, - isError, - data, - error, - refetch, - isFetching - } = useQuery({ - queryKey: ['todos'], - queryFn: fetchTodoList, - enabled: false, - }) + const { isInitialLoading, isError, data, error, refetch, isFetching } = + useQuery({ + queryKey: ['todos'], + queryFn: fetchTodoList, + enabled: false, + }) return (
@@ -36,21 +32,17 @@ function Todos() { {data ? ( <>
    - {data.map(todo => ( + {data.map((todo) => (
  • {todo.title}
  • ))}
+ ) : isError ? ( + Error: {error.message} + ) : isInitialLoading ? ( + Loading... ) : ( - isError ? ( - Error: {error.message} - ) : ( - isInitialLoading ? ( - Loading... - ) : ( - Not ready ... - ) - ) + Not ready ... )}
{isFetching ? 'Fetching...' : null}
@@ -59,12 +51,16 @@ function Todos() { } ``` -Permanently disabling a query opts out of many great features that react-query has to offer (like background refetches), and it's also not the idiomatic way. It takes you from the declarative approach (defining dependencies when your query should run) into an imperative mode (fetch whenever I click here). It is also not possible to pass parameters to `refetch`. Oftentimes, all you want is a lazy query that defers the initial fetch: +[//]: # 'Example' + +Permanently disabling a query opts out of many great features that Tanstack Query has to offer (like background refetches), and it's also not the idiomatic way. It takes you from the declarative approach (defining dependencies when your query should run) into an imperative mode (fetch whenever I click here). It is also not possible to pass parameters to `refetch`. Oftentimes, all you want is a lazy query that defers the initial fetch: ## Lazy Queries The enabled option can not only be used to permanently disable a query, but also to enable / disable it at a later time. A good example would be a filter form where you only want to fire off the first request once the user has entered a filter value: +[//]: # 'Example2' + ```tsx function Todos() { const [filter, setFilter] = React.useState('') @@ -86,6 +82,8 @@ function Todos() { } ``` +[//]: # 'Example2' + ### isInitialLoading Lazy queries will be in `status: 'loading'` right from the start because `loading` means that there is no data yet. This is technically true, however, since we are not currently fetching any data (as the query is not _enabled_), it also means you likely cannot use this flag to show a loading spinner. diff --git a/docs/react/guides/does-this-replace-client-state.md b/docs/react/guides/does-this-replace-client-state.md index 35a95cf656..3d7ead4efd 100644 --- a/docs/react/guides/does-this-replace-client-state.md +++ b/docs/react/guides/does-this-replace-client-state.md @@ -1,18 +1,18 @@ --- id: does-this-replace-client-state -title: Does React Query replace Redux, MobX or other global state managers? +title: Does Tanstack Query replace Redux, MobX or other global state managers? --- Well, let's start with a few important items: -- React Query is a **server-state** library, responsible for managing asynchronous operations between your server and client -- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like React Query_ +- Tanstack Query is a **server-state** library, responsible for managing asynchronous operations between your server and client +- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like Tanstack Query_ -With those points in mind, the short answer is that React Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** +With those points in mind, the short answer is that Tanstack Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** -For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to React Query is usually very tiny. +For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to Tanstack Query is usually very tiny. -> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **React Query is not a replacement for local/client state management**. However, you can use React Query along side most client state managers with zero issues. +> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **Tanstack Query is not a replacement for local/client state management**. However, you can use Tanstack Query along side most client state managers with zero issues. ## A Contrived Example @@ -29,7 +29,7 @@ const globalState = { } ``` -Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to React Query, our remaining global state would look more like this: +Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to Tanstack Query, our remaining global state would look more like this: ```tsx const globalState = { @@ -51,6 +51,6 @@ With all of those things removed, you may ask yourself, **"Is it worth it to kee **And that's up to you!** -But React Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. +But Tanstack Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. What are you waiting for, give it a go already! diff --git a/docs/react/guides/filters.md b/docs/react/guides/filters.md index 1de642b603..44c8e0997f 100644 --- a/docs/react/guides/filters.md +++ b/docs/react/guides/filters.md @@ -3,7 +3,7 @@ id: filters title: Filters --- -Some methods within React Query accept a `QueryFilters` or `MutationFilters` object. +Some methods within Tanstack Query accept a `QueryFilters` or `MutationFilters` object. ## `Query Filters` diff --git a/docs/react/guides/important-defaults.md b/docs/react/guides/important-defaults.md index 4dee502255..1721cb4563 100644 --- a/docs/react/guides/important-defaults.md +++ b/docs/react/guides/important-defaults.md @@ -3,7 +3,7 @@ id: important-defaults title: Important Defaults --- -Out of the box, React Query is configured with **aggressive but sane** defaults. **Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.** Keep them in mind as you continue to learn and use React Query: +Out of the box, Tanstack Query is configured with **aggressive but sane** defaults. **Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.** Keep them in mind as you continue to learn and use Tanstack Query: - Query instances via `useQuery` or `useInfiniteQuery` by default **consider cached data as stale**. @@ -15,7 +15,7 @@ Out of the box, React Query is configured with **aggressive but sane** defaults. - The network is reconnected - The query is optionally configured with a refetch interval -If you see a refetch that you are not expecting, it is likely because you just focused the window and React Query is doing a [`refetchOnWindowFocus`](../guides/window-focus-refetching). During development, this will probably be triggered more frequently, especially because focusing between the Browser DevTools and your app will also cause a fetch, so be aware of that. +If you see a refetch that you are not expecting, it is likely because you just focused the window and Tanstack Query is doing a [`refetchOnWindowFocus`](../guides/window-focus-refetching). During development, this will probably be triggered more frequently, especially because focusing between the Browser DevTools and your app will also cause a fetch, so be aware of that. > To change this functionality, you can use options like `refetchOnMount`, `refetchOnWindowFocus`, `refetchOnReconnect` and `refetchInterval`. @@ -32,9 +32,13 @@ If you see a refetch that you are not expecting, it is likely because you just f > Structural sharing only works with JSON-compatible values, any other value types will always be considered as changed. If you are seeing performance issues because of large responses for example, you can disable this feature with the `config.structuralSharing` flag. If you are dealing with non-JSON compatible values in your query responses and still want to detect if data has changed or not, you can define a data compare function with `config.isDataEqual` or provide your own custom function as `config.structuralSharing` to compute a value from the old and new responses, retaining references as required. +[//]: # 'Materials' + ## Further Reading Have a look at the following articles from our Community Resources for further explanations of the defaults: - [Practical React Query](../community/tkdodos-blog#1-practical-react-query) - [React Query as a State Manager](../community/tkdodos-blog#10-react-query-as-a-state-manager) + +[//]: # 'Materials' diff --git a/docs/react/guides/infinite-queries.md b/docs/react/guides/infinite-queries.md index 79734607cc..8c55e9041f 100644 --- a/docs/react/guides/infinite-queries.md +++ b/docs/react/guides/infinite-queries.md @@ -3,7 +3,7 @@ id: infinite-queries title: Infinite Queries --- -Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. React Query supports a useful version of `useQuery` called `useInfiniteQuery` for querying these types of lists. +Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. Tanstack Query supports a useful version of `useQuery` called `useInfiniteQuery` for querying these types of lists. When using `useInfiniteQuery`, you'll notice a few things are different: @@ -41,13 +41,15 @@ With this information, we can create a "Load More" UI by: > Note: It's very important you do not call `fetchNextPage` with arguments unless you want them to override the `pageParam` data returned from the `getNextPageParam` function. e.g. Do not do this: ` @@ -115,14 +131,18 @@ const CreateTodo = () => { } ``` +[//]: # 'Example3' + ## Mutation Side Effects `useMutation` comes with some helper options that allow quick and easy side-effects at any stage during the mutation lifecycle. These come in handy for both [invalidating and refetching queries after mutations](../guides/invalidations-from-mutations) and even [optimistic updates](../guides/optimistic-updates) +[//]: # 'Example4' + ```tsx useMutation({ mutationFn: addTodo, - onMutate: variables => { + onMutate: (variables) => { // A mutation is about to happen! // Optionally return a context containing data to use when for example rolling back @@ -141,8 +161,12 @@ useMutation({ }) ``` +[//]: # 'Example4' + When returning a promise in any of the callback functions it will first be awaited before the next callback is called: +[//]: # 'Example5' + ```tsx useMutation({ mutationFn: addTodo, @@ -155,8 +179,12 @@ useMutation({ }) ``` +[//]: # 'Example5' + You might find that you want to **trigger additional callbacks** beyond the ones defined on `useMutation` when calling `mutate`. This can be used to trigger component-specific side effects. To do that, you can provide any of the same callback options to the `mutate` function after your mutation variable. Supported overrides include: `onSuccess`, `onError` and `onSettled`. Please keep in mind that those additional callbacks won't run if your component unmounts _before_ the mutation finishes. +[//]: # 'Example6' + ```tsx useMutation({ mutationFn: addTodo, @@ -184,20 +212,23 @@ mutate(todo, { }) ``` +[//]: # 'Example6' + ### Consecutive mutations -There is a slight difference in handling `onSuccess`, `onError` and `onSettled` callbacks when it comes to consecutive mutations. When passed to the `mutate` function, they will be fired up only _once_ and only if the component is still mounted. This is due to the fact that mutation observer is removed and resubscribed every time when the `mutate` function is called. On the contrary, `useMutation` handlers execute for each `mutate` call. + +There is a slight difference in handling `onSuccess`, `onError` and `onSettled` callbacks when it comes to consecutive mutations. When passed to the `mutate` function, they will be fired up only _once_ and only if the component is still mounted. This is due to the fact that mutation observer is removed and resubscribed every time when the `mutate` function is called. On the contrary, `useMutation` handlers execute for each `mutate` call. > Be aware that most likely, `mutationFn` passed to `useMutation` is asynchronous. In that case, the order in which mutations are fulfilled may differ from the order of `mutate` function calls. +[//]: # 'Example7' + ```tsx useMutation({ mutationFn: addTodo, onSuccess: (data, error, variables, context) => { // Will be called 3 times }, -}) - -['Todo 1', 'Todo 2', 'Todo 3'].forEach((todo) => { +})[('Todo 1', 'Todo 2', 'Todo 3')].forEach((todo) => { mutate(todo, { onSuccess: (data, error, variables, context) => { // Will execute only once, for the last mutation (Todo 3), @@ -205,12 +236,16 @@ useMutation({ }, }) }) - ``` + +[//]: # 'Example7' + ## Promises Use `mutateAsync` instead of `mutate` to get a promise which will resolve on success or throw on an error. This can for example be used to compose side effects. +[//]: # 'Example8' + ```tsx const mutation = useMutation({ mutationFn: addTodo }) @@ -224,9 +259,13 @@ try { } ``` +[//]: # 'Example8' + ## Retry -By default React 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' ```tsx const mutation = useMutation({ @@ -235,12 +274,16 @@ const mutation = useMutation({ }) ``` +[//]: # 'Example9' + If mutations fail because the device is offline, they will be retried in the same order when the device reconnects. ## Persist mutations Mutations can be persisted to storage if needed and resumed at a later point. This can be done with the hydration functions: +[//]: # 'Example10' + ```tsx const queryClient = new QueryClient() @@ -255,18 +298,24 @@ queryClient.setMutationDefaults(['addTodo'], { const optimisticTodo = { id: uuid(), title: variables.title } // Add optimistic todo to todos list - queryClient.setQueryData(['todos'], old => [...old, optimisticTodo]) + queryClient.setQueryData(['todos'], (old) => [...old, optimisticTodo]) // Return context with the optimistic todo return { optimisticTodo } }, onSuccess: (result, variables, context) => { // Replace optimistic todo in the todos list with the result - queryClient.setQueryData(['todos'], old => old.map(todo => todo.id === context.optimisticTodo.id ? result : todo)) + queryClient.setQueryData(['todos'], (old) => + old.map((todo) => + todo.id === context.optimisticTodo.id ? result : todo, + ), + ) }, onError: (error, variables, context) => { // Remove optimistic todo from the todos list - queryClient.setQueryData(['todos'], old => old.filter(todo => todo.id !== context.optimisticTodo.id)) + queryClient.setQueryData(['todos'], (old) => + old.filter((todo) => todo.id !== context.optimisticTodo.id), + ) }, retry: 3, }) @@ -286,12 +335,16 @@ hydrate(queryClient, state) queryClient.resumePausedMutations() ``` +[//]: # 'Example10' + ### Persisting Offline mutations If you persist offline mutations with the [persistQueryClient plugin](../plugins/persistQueryClient), mutations cannot be resumed when the page is reloaded unless you provide a default mutation function. This is a technical limitation. When persisting to an external storage, only the state of mutations is persisted, as functions cannot be serialized. After hydration, the component that triggers the mutation might not be mounted, so calling `resumePausedMutations` might yield an error: `No mutationFn found`. +[//]: # 'Example11' + ```tsx const persister = createSyncStoragePersister({ storage: window.localStorage, @@ -327,9 +380,15 @@ export default function App() { } ``` +[//]: # 'Example11' + We also have an extensive [offline example](../examples/react/offline) that covers both queries and mutations. +[//]: # 'Materials' + ## 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 the Community Resources. + +[//]: # 'Materials' diff --git a/docs/react/guides/testing.md b/docs/react/guides/testing.md index 8c983ac19a..350e526d7b 100644 --- a/docs/react/guides/testing.md +++ b/docs/react/guides/testing.md @@ -21,7 +21,7 @@ npm install @testing-library/react-hooks react-test-renderer --save-dev Once installed, a simple test can be written. Given the following custom hook: -```ts +```tsx export function useCustomHook() { return useQuery({ queryKey: ['customHook'], queryFn: () => 'Hello' }); } @@ -87,7 +87,7 @@ This will set the defaults for all queries in the component tree to "no retries" When testing we want to suppress network errors being logged to the console. To do this, we can pass a custom logger to `QueryClient`: -```ts +```tsx import { QueryClient } from '@tanstack/react-query' const queryClient = new QueryClient({ @@ -112,7 +112,7 @@ There are plenty of ways that these can be tested, but for this example we are g Given the following custom hook: -```ts +```tsx function useFetchData() { return useQuery({ queryKey: ['fetchData'], @@ -152,7 +152,7 @@ Here we are making use of `waitFor` and waiting until the query status indicates First we need to mock our API response -```ts +```tsx function generateMockedResponse(page) { return { page: page, @@ -164,7 +164,7 @@ function generateMockedResponse(page) { Then, our `nock` configuration needs to differentiate responses based on the page, and we'll be using `uri` to do this. `uri`'s value here will be something like `"/?page=1` or `/?page=2` -```ts +```tsx const expectation = nock('http://example.com') .persist() .query(true) @@ -180,7 +180,7 @@ const expectation = nock('http://example.com') Now we can safely run our tests, the trick here is to await for the data assertion to pass: -```ts +```tsx const { result, waitFor } = renderHook( () => useInfiniteQueryCustomHook(), { wrapper }, diff --git a/docs/react/plugins/broadcastQueryClient.md b/docs/react/plugins/broadcastQueryClient.md index 1d06322a69..6b33e01c51 100644 --- a/docs/react/plugins/broadcastQueryClient.md +++ b/docs/react/plugins/broadcastQueryClient.md @@ -15,7 +15,7 @@ This utility comes as a separate package and is available under the `'@tanstack/ Import the `broadcastQueryClient` function, and pass it your `QueryClient` instance, and optionally, set a `broadcastChannel`. -```ts +```tsx import { broadcastQueryClient } from '@tanstack/query-broadcast-client-experimental' const queryClient = new QueryClient() @@ -32,7 +32,7 @@ broadcastQueryClient({ Pass this function a `QueryClient` instance and optionally, a `broadcastChannel`. -```ts +```tsx broadcastQueryClient({ queryClient, broadcastChannel }) ``` @@ -40,7 +40,7 @@ broadcastQueryClient({ queryClient, broadcastChannel }) An object of options: -```ts +```tsx interface broadcastQueryClient { /** The QueryClient to sync */ queryClient: QueryClient @@ -52,7 +52,7 @@ interface broadcastQueryClient { The default options are: -```ts +```tsx { broadcastChannel = 'react-query', } diff --git a/docs/react/plugins/createAsyncStoragePersister.md b/docs/react/plugins/createAsyncStoragePersister.md index 39569b2816..d2107bce66 100644 --- a/docs/react/plugins/createAsyncStoragePersister.md +++ b/docs/react/plugins/createAsyncStoragePersister.md @@ -25,7 +25,7 @@ yarn add @tanstack/query-async-storage-persister @tanstack/react-query-persist-c - you can pass any `storage` to it that adheres to the `AsyncStorage` interface - the example below uses the async-storage from React Native - Wrap your app by using [`PersistQueryClientProvider`](../plugins/persistQueryClient.md#persistqueryclientprovider) component. -```ts +```tsx import AsyncStorage from '@react-native-async-storage/async-storage' import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client' import { createAsyncStoragePersister } from '@tanstack/query-async-storage-persister' @@ -70,7 +70,7 @@ createAsyncStoragePersister(options: CreateAsyncStoragePersisterOptions) ### `Options` -```ts +```tsx interface CreateAsyncStoragePersisterOptions { /** The storage client used for setting an retrieving items from cache */ storage: AsyncStorage diff --git a/docs/react/plugins/createSyncStoragePersister.md b/docs/react/plugins/createSyncStoragePersister.md index b2e80b91ad..46c28f1bb5 100644 --- a/docs/react/plugins/createSyncStoragePersister.md +++ b/docs/react/plugins/createSyncStoragePersister.md @@ -24,7 +24,7 @@ yarn add @tanstack/query-sync-storage-persister @tanstack/react-query-persist-cl - Create a new syncStoragePersister - Pass it to the [`persistQueryClient`](../plugins/persistQueryClient) function -```ts +```tsx import { persistQueryClient } from '@tanstack/react-query-persist-client' import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister' @@ -51,7 +51,7 @@ Persistence can fail, e.g. if the size exceeds the available space on the storag The retry function receives the `persistedClient` it tried to save, as well as the `error` and the `errorCount` as input. It is expected to return a _new_ `PersistedClient`, with which it tries to persist again. If _undefined_ is returned, there will be no further attempt to persist. -```ts +```tsx export type PersistRetryer = (props: { persistedClient: PersistedClient error: Error @@ -85,7 +85,7 @@ createSyncStoragePersister(options: CreateSyncStoragePersisterOptions) ### `Options` -```ts +```tsx interface CreateSyncStoragePersisterOptions { /** The storage client used for setting an retrieving items from cache (window.localStorage or window.sessionStorage) */ storage: Storage diff --git a/docs/react/plugins/persistQueryClient.md b/docs/react/plugins/persistQueryClient.md index b20613d6fa..dc2b2f00eb 100644 --- a/docs/react/plugins/persistQueryClient.md +++ b/docs/react/plugins/persistQueryClient.md @@ -21,7 +21,7 @@ It should be set as the same value or higher than persistQueryClient's `maxAge` You can also pass it `Infinity` to disable garbage collection behavior entirely. -```ts +```tsx const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -35,7 +35,7 @@ const queryClient = new QueryClient({ Sometimes you may make changes to your application or data that immediately invalidate any and all cached data. If and when this happens, you can pass a `buster` string option. If the cache that is found does not also have that buster string, it will be discarded. The following several functions accept this option: -```ts +```tsx persistQueryClient({ queryClient, persister, buster: buildHash }) persistQueryClientSave({ queryClient, persister, buster: buildHash }) persistQueryClientRestore({ queryClient, persister, buster: buildHash }) @@ -61,7 +61,7 @@ the persister `removeClient()` is called and the cache is immediately discarded. You can use this to explicitly persist the cache at the moment(s) you choose. -```ts +```tsx persistQueryClientSave({ queryClient, persister, @@ -77,7 +77,7 @@ Runs `persistQueryClientSave` whenever the cache changes for your `queryClient`. - It returns an `unsubscribe` function which you can use to discontinue the monitor; ending the updates to the persisted cache. - If you want to erase the persisted cache after the `unsubscribe`, you can send a new `buster` to `persistQueryClientRestore` which will trigger the persister's `removeClient` function and discard the persisted cache. -```ts +```tsx persistQueryClientSubscribe({ queryClient, persister, @@ -93,7 +93,7 @@ persistQueryClientSubscribe({ You can use this to restore the cache at moment(s) you choose. -```ts +```tsx persistQueryClientRestore({ queryClient, persister, @@ -112,7 +112,7 @@ Takes the following actions: This functionality is preserved from version 3.x. -```ts +```tsx persistQueryClient({ queryClient, persister, @@ -127,7 +127,7 @@ persistQueryClient({ All options available are as follows: -```ts +```tsx interface PersistQueryClientOptions { /** The QueryClient to persist */ queryClient: QueryClient @@ -227,7 +227,7 @@ If you are using the `PersistQueryClientProvider`, you can also use the `useIsRe Persisters have the following interfaces: -```ts +```tsx export interface Persister { persistClient(persistClient: PersistedClient): Promisable restoreClient(): Promisable @@ -237,7 +237,7 @@ export interface Persister { Persisted Client entries have the following interface: -```ts +```tsx export interface PersistedClient { timestamp: number buster: string @@ -246,14 +246,14 @@ export interface PersistedClient { ``` You can import these (to build a persister): -```ts +```tsx import { PersistedClient, Persister } from "@tanstack/react-query-persist-client"; ``` ### Building A Persister You can persist however you like. Here is an example of how to build an [Indexed DB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) persister. Compared to `Web Storage API`, Indexed DB is faster, stores more than 5MB, and doesn't require serialization. That means it can readily store Javascript native types, such as `Date` and `File`. -```ts +```tsx import { get, set, del } from "idb-keyval"; import { PersistedClient, Persister } from "@tanstack/react-query-persist-client"; diff --git a/docs/react/react-native.md b/docs/react/react-native.md index 5992b1aecf..047918e959 100644 --- a/docs/react/react-native.md +++ b/docs/react/react-native.md @@ -14,7 +14,7 @@ If you would like to help us make the built-in devtools platform agnostic, pleas React Query already supports auto refetch on reconnect in web browser. To add this behavior in React Native you have to use React Query `onlineManager` as in the example below: -```ts +```tsx import NetInfo from '@react-native-community/netinfo' import { onlineManager } from '@tanstack/react-query' @@ -29,7 +29,7 @@ onlineManager.setEventListener(setOnline => { Instead of event listeners on `window`, React Native provides focus information through the [`AppState` module](https://reactnative.dev/docs/appstate#app-states). You can use the `AppState` "change" event to trigger an update when the app state changes to "active": -```ts +```tsx import { useEffect } from "react" import { AppState, Platform } from 'react-native' import type { AppStateStatus } from "react-native" @@ -53,7 +53,7 @@ useEffect(() => { In some situations, you may want to refetch the query when a React Native Screen is focused again. This custom hook will call the provided `refetch` function when the screen is focused again. -```ts +```tsx import React from 'react' import { useFocusEffect } from '@react-navigation/native' diff --git a/docs/react/typescript.md b/docs/react/typescript.md index 5800ec614f..004daad70e 100644 --- a/docs/react/typescript.md +++ b/docs/react/typescript.md @@ -16,7 +16,7 @@ Things to keep in mind: Types in React Query generally flow through very well so that you don't have to provide type annotations for yourself -```ts +```tsx const { data } = useQuery({ // ^? const data: number | undefined queryKey: ['test'], @@ -30,7 +30,7 @@ const { data } = useQuery({ [//]: # 'Playground1' -```ts +```tsx const { data } = useQuery({ // ^? const data: string | undefined queryKey: ['test'], @@ -47,7 +47,7 @@ const { data } = useQuery({ This works best if your `queryFn` has a well-defined returned type. Keep in mind that most data fetching libraries return `any` per default, so make sure to extract it to a properly typed function: -```ts +```tsx const fetchGroups = (): Promise => axios.get('/groups').then((response) => response.data) @@ -65,7 +65,7 @@ const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups }) React Query uses a [discriminated union type](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-func.html#discriminated-unions) for the query result, discriminated by the `status` field and the derived status boolean flags. This will allow you to check for e.g. `success` status to make `data` defined: -```ts +```tsx const { data, isSuccess } = useQuery({ queryKey: ['test'], queryFn: () => Promise.resolve(5), @@ -87,7 +87,7 @@ if (isSuccess) { The type for error defaults to `unknown`. This is in line with what TypeScript gives you per default in a catch clauses (see [useUnknownInCatchVariables](https://devblogs.microsoft.com/typescript/announcing-typescript-4-4/#use-unknown-catch-variables)). The safest way to work with `error` would be to perform a runtime check; another way would be to explicitly define types for `data` and `error`: -```ts +```tsx const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups }) // ^? const error: unknown @@ -103,7 +103,7 @@ if (error instanceof Error) { [//]: # 'Playground5' -```ts +```tsx const { error } = useQuery(['groups'], fetchGroups) // ^? const error: Error | null ``` diff --git a/docs/vue/guides/background-fetching-indicators.md b/docs/vue/guides/background-fetching-indicators.md index 22b96f8902..125a176950 100644 --- a/docs/vue/guides/background-fetching-indicators.md +++ b/docs/vue/guides/background-fetching-indicators.md @@ -2,7 +2,6 @@ id: background-fetching-indicators title: Background Fetching Indicators ref: docs/react/guides/background-fetching-indicators.md -replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- [//]: # 'Example' diff --git a/docs/vue/guides/caching.md b/docs/vue/guides/caching.md index bfb8628f43..4783eddc0f 100644 --- a/docs/vue/guides/caching.md +++ b/docs/vue/guides/caching.md @@ -2,5 +2,4 @@ id: caching title: Caching Examples ref: docs/react/guides/caching.md -replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- diff --git a/docs/vue/guides/custom-client.md b/docs/vue/guides/custom-client.md index ef1839c5f0..0b3e6d19f9 100644 --- a/docs/vue/guides/custom-client.md +++ b/docs/vue/guides/custom-client.md @@ -1,3 +1,8 @@ +--- +id: custom-client +title: Custom Client +--- + ### Custom client Vue Query allows providing custom `QueryClient` for Vue context. @@ -8,7 +13,7 @@ For this reason, `VueQueryPlugin` accepts either `QueryClientConfig` or `QueryCl If You provide `QueryClientConfig`, `QueryClient` instance will be created internally and provided to Vue context. -```ts +```tsx const vueQueryPluginOptions: VueQueryPluginOptions = { queryClientConfig: { defaultOptions: { queries: { staleTime: 3600 } }, @@ -17,7 +22,7 @@ const vueQueryPluginOptions: VueQueryPluginOptions = { app.use(VueQueryPlugin, vueQueryPluginOptions) ``` -```ts +```tsx const myClient = new QueryClient(queryClientConfig) const vueQueryPluginOptions: VueQueryPluginOptions = { queryClient: myClient, @@ -31,14 +36,14 @@ You can also customize the key under which `QueryClient` will be accessible in V It works both with default, and custom `QueryClient` -```ts +```tsx const vueQueryPluginOptions: VueQueryPluginOptions = { queryClientKey: 'Foo', } app.use(VueQueryPlugin, vueQueryPluginOptions) ``` -```ts +```tsx const myClient = new QueryClient(queryClientConfig) const vueQueryPluginOptions: VueQueryPluginOptions = { queryClient: myClient, @@ -55,7 +60,7 @@ useQuery('query1', fetcher, { queryClientKey: 'foo' }) Internally custom key will be combined with default query key as a suffix. But user do not have to worry about it. -```ts +```tsx const vueQueryPluginOptions: VueQueryPluginOptions = { queryClientKey: 'Foo', } diff --git a/docs/vue/guides/custom-logger.md b/docs/vue/guides/custom-logger.md index bcbf58ebfc..fe6d7ce393 100644 --- a/docs/vue/guides/custom-logger.md +++ b/docs/vue/guides/custom-logger.md @@ -2,5 +2,4 @@ id: custom-logger title: Custom Logger ref: docs/react/guides/custom-logger.md -replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- diff --git a/docs/vue/guides/default-query-function.md b/docs/vue/guides/default-query-function.md index d400bfa802..4b004497d4 100644 --- a/docs/vue/guides/default-query-function.md +++ b/docs/vue/guides/default-query-function.md @@ -2,7 +2,6 @@ id: default-query-function title: Default Query Function ref: docs/react/guides/default-query-function.md -replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- [//]: # 'Example' diff --git a/docs/vue/guides/dependent-queries.md b/docs/vue/guides/dependent-queries.md index d957d7b729..bfad03a546 100644 --- a/docs/vue/guides/dependent-queries.md +++ b/docs/vue/guides/dependent-queries.md @@ -2,7 +2,6 @@ id: dependent-queries title: Dependent Queries ref: docs/react/guides/dependent-queries.md -replace: { 'React': 'Vue', 'react-query': 'vue-query' } --- [//]: # 'Example' diff --git a/docs/vue/guides/disabling-queries.md b/docs/vue/guides/disabling-queries.md new file mode 100644 index 0000000000..6be1a715cd --- /dev/null +++ b/docs/vue/guides/disabling-queries.md @@ -0,0 +1,56 @@ +--- +id: disabling-queries +title: Disabling/Pausing Queries +ref: docs/react/guides/disabling-queries.md +--- + +[//]: # 'Example' + +```vue + + + +``` + +[//]: # 'Example' +[//]: # 'Example2' + +```vue + + + +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/does-this-replace-client-state.md b/docs/vue/guides/does-this-replace-client-state.md new file mode 100644 index 0000000000..63d8ff8937 --- /dev/null +++ b/docs/vue/guides/does-this-replace-client-state.md @@ -0,0 +1,59 @@ +--- +id: does-this-replace-client-state +title: Does Vue Query replace Vuex, Pinia or other global state managers? +ref: docs/react/guides/does-this-replace-client-state.md +replace: + { 'Redux, MobX': 'Vuex, Pinia' } +--- + +Well, let's start with a few important items: + +- React Query is a **server-state** library, responsible for managing asynchronous operations between your server and client +- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like React Query_ + +With those points in mind, the short answer is that React Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** + +For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to React Query is usually very tiny. + +> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **React Query is not a replacement for local/client state management**. However, you can use React Query along side most client state managers with zero issues. + +## A Contrived Example + +Here we have some "global" state being managed by a global state library: + +```tsx +const globalState = { + projects, + teams, + tasks, + users, + themeMode, + sidebarStatus, +} +``` + +Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to React Query, our remaining global state would look more like this: + +```tsx +const globalState = { + themeMode, + sidebarStatus, +} +``` + +This also means that with a few hook calls to `useQuery` and `useMutation`, we also get to remove any boilerplate code that was used to manage our server state eg. + +- Connectors +- Action Creators +- Middlewares +- Reducers +- Loading/Error/Result states +- Contexts + +With all of those things removed, you may ask yourself, **"Is it worth it to keep using our client state manager for this tiny global state?"** + +**And that's up to you!** + +But React Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. + +What are you waiting for, give it a go already! diff --git a/docs/vue/guides/filters.md b/docs/vue/guides/filters.md new file mode 100644 index 0000000000..a92a902b48 --- /dev/null +++ b/docs/vue/guides/filters.md @@ -0,0 +1,5 @@ +--- +id: filters +title: Filters +ref: docs/react/guides/filters.md +--- diff --git a/docs/vue/guides/important-defaults.md b/docs/vue/guides/important-defaults.md new file mode 100644 index 0000000000..083145cfb5 --- /dev/null +++ b/docs/vue/guides/important-defaults.md @@ -0,0 +1,8 @@ +--- +id: important-defaults +title: Important Defaults +ref: docs/react/guides/important-defaults.md +--- + +[//]: # 'Materials' +[//]: # 'Materials' diff --git a/docs/vue/guides/infinite-queries.md b/docs/vue/guides/infinite-queries.md new file mode 100644 index 0000000000..18dc2cbf4b --- /dev/null +++ b/docs/vue/guides/infinite-queries.md @@ -0,0 +1,88 @@ +--- +id: infinite-queries +title: Infinite Queries +ref: docs/react/guides/infinite-queries.md +--- + +[//]: # 'Example' + +```vue + + + +``` + +[//]: # 'Example' +[//]: # 'Example3' + +```tsx +const fetchProjects = ({ pageParam = 0 }) => + fetch('/api/projects?cursor=' + pageParam) + +const { fetchNextPage } = useInfiniteQuery({ + queryKey: ['projects'], + queryFn: fetchProjects, + getNextPageParam: (lastPage, pages) => lastPage.nextCursor, +}) + +// Pass your own page param +const skipToCursor50 = () => fetchNextPage({ pageParam: 50 }) +``` + +[//]: # 'Example3' +[//]: # 'Example7' + +```tsx +const newPagesArray = + oldPagesArray?.pages.map((page) => + page.filter((val) => val.id !== updatedId), + ) ?? [] + +queryClient.setQueryData(['projects'], (data) => ({ + pages: newPagesArray, + pageParams: data.pageParams, +})) +``` + +[//]: # 'Example7' diff --git a/docs/vue/guides/initial-query-data.md b/docs/vue/guides/initial-query-data.md new file mode 100644 index 0000000000..1654c07b7c --- /dev/null +++ b/docs/vue/guides/initial-query-data.md @@ -0,0 +1,5 @@ +--- +id: initial-query-data +title: Initial Query Data +ref: docs/react/guides/initial-query-data.md +--- diff --git a/docs/vue/guides/invalidations-from-mutations.md b/docs/vue/guides/invalidations-from-mutations.md new file mode 100644 index 0000000000..5059d654ae --- /dev/null +++ b/docs/vue/guides/invalidations-from-mutations.md @@ -0,0 +1,24 @@ +--- +id: invalidations-from-mutations +title: Invalidations from Mutations +ref: docs/react/guides/invalidations-from-mutations.md +--- + +[//]: # 'Example2' + +```tsx +import { useMutation, useQueryClient } from '@tanstack/vue-query' + +const queryClient = useQueryClient() + +// When this mutation succeeds, invalidate any queries with the `todos` or `reminders` query key +const mutation = useMutation({ + mutationFn: addTodo, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['todos'] }) + queryClient.invalidateQueries({ queryKey: ['reminders'] }) + }, +}) +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/mutations.md b/docs/vue/guides/mutations.md new file mode 100644 index 0000000000..d8d2a23bd5 --- /dev/null +++ b/docs/vue/guides/mutations.md @@ -0,0 +1,5 @@ +--- +id: mutations +title: Mutations +ref: docs/react/guides/mutations.md +--- diff --git a/docs/vue/installation.md b/docs/vue/installation.md index bdbabca3aa..70ec75d080 100644 --- a/docs/vue/installation.md +++ b/docs/vue/installation.md @@ -25,7 +25,7 @@ Vue Query is compatible with Vue 2.x and 3.x Before using Vue Query, you need to initialize it using `VueQueryPlugin` -```ts +```tsx import { VueQueryPlugin } from "@tanstack/vue-query"; app.use(VueQueryPlugin) diff --git a/packages/vue-query/README.md b/packages/vue-query/README.md index e61b61915c..a882b1c09a 100644 --- a/packages/vue-query/README.md +++ b/packages/vue-query/README.md @@ -46,7 +46,7 @@ Visit https://tanstack.com/query/v4/docs/adapters/vue-query 2. Initialize **Vue Query** via **VueQueryPlugin** - ```ts + ```tsx import { createApp } from "vue"; import { VueQueryPlugin } from "@tanstack/vue-query"; @@ -57,7 +57,7 @@ Visit https://tanstack.com/query/v4/docs/adapters/vue-query 3. Use query - ```ts + ```tsx import { defineComponent } from "vue"; import { useQuery } from "@tanstack/vue-query"; @@ -75,7 +75,7 @@ Visit https://tanstack.com/query/v4/docs/adapters/vue-query 4. If you need to update options on your query dynamically, make sure to pass them as reactive variables - ```ts + ```tsx const id = ref(1); const enabled = ref(false); From de3926fc28977921f49f67d30f9b3961559cc60d Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Mon, 26 Dec 2022 15:20:32 +0100 Subject: [PATCH 3/7] docs: vue-query docs part 3 --- docs/react/guides/mutations.md | 7 +- docs/react/guides/network-mode.md | 10 +- docs/react/guides/optimistic-updates.md | 22 ++++- docs/react/guides/paginated-queries.md | 8 +- docs/react/guides/parallel-queries.md | 19 +++- docs/react/guides/placeholder-query-data.md | 21 +++- docs/react/guides/prefetching.md | 10 +- docs/react/guides/queries.md | 25 ++++- docs/vue/guides/custom-client.md | 6 +- docs/vue/guides/mutations.md | 92 +++++++++++++++++ docs/vue/guides/network-mode.md | 6 ++ docs/vue/guides/optimistic-updates.md | 103 ++++++++++++++++++++ docs/vue/guides/paginated-queries.md | 53 ++++++++++ docs/vue/guides/parallel-queries.md | 38 ++++++++ docs/vue/guides/placeholder-query-data.md | 40 ++++++++ docs/vue/guides/prefetching.md | 5 + docs/vue/guides/queries.md | 63 ++++++++++++ 17 files changed, 504 insertions(+), 24 deletions(-) create mode 100644 docs/vue/guides/network-mode.md create mode 100644 docs/vue/guides/optimistic-updates.md create mode 100644 docs/vue/guides/paginated-queries.md create mode 100644 docs/vue/guides/parallel-queries.md create mode 100644 docs/vue/guides/placeholder-query-data.md create mode 100644 docs/vue/guides/prefetching.md create mode 100644 docs/vue/guides/queries.md diff --git a/docs/react/guides/mutations.md b/docs/react/guides/mutations.md index b1fa854b88..43f8c4bd5d 100644 --- a/docs/react/guides/mutations.md +++ b/docs/react/guides/mutations.md @@ -62,9 +62,10 @@ In the example above, you also saw that you can pass variables to your mutations Even with just variables, mutations aren't all that special, but when used with the `onSuccess` option, the [Query Client's `invalidateQueries` method](../reference/QueryClient#queryclientinvalidatequeries) and the [Query Client's `setQueryData` method](../reference/QueryClient#queryclientsetquerydata), mutations become a very powerful tool. [//]: # 'Info1' + > IMPORTANT: The `mutate` function is an asynchronous function, which means you cannot use it directly in an event callback in **React 16 and earlier**. If you need to access the event in `onSubmit` you need to wrap `mutate` in another function. This is due to [React event pooling](https://reactjs.org/docs/legacy-event-pooling.html). -[//]: # 'Info1' +[//]: # 'Info1' [//]: # 'Example2' ```tsx @@ -228,7 +229,9 @@ useMutation({ onSuccess: (data, error, variables, context) => { // Will be called 3 times }, -})[('Todo 1', 'Todo 2', 'Todo 3')].forEach((todo) => { +}) + +[('Todo 1', 'Todo 2', 'Todo 3')].forEach((todo) => { mutate(todo, { onSuccess: (data, error, variables, context) => { // Will execute only once, for the last mutation (Todo 3), diff --git a/docs/react/guides/network-mode.md b/docs/react/guides/network-mode.md index 96c18892d9..be3987ee26 100644 --- a/docs/react/guides/network-mode.md +++ b/docs/react/guides/network-mode.md @@ -3,9 +3,9 @@ id: network-mode title: Network Mode --- -React Query provides three different network modes to distinguish how [Queries](../guides/queries) and [Mutations](../guides/mutations) should behave if you have no network connection. This mode can be set for each Query / Mutation individually, or globally via the query / mutation defaults. +Tanstack Query provides three different network modes to distinguish how [Queries](../guides/queries) and [Mutations](../guides/mutations) should behave if you have no network connection. This mode can be set for each Query / Mutation individually, or globally via the query / mutation defaults. -Since React Query is most often used for data fetching in combination with data fetching libraries, the default network mode is [online](#network-mode-online). +Since Tanstack Query is most often used for data fetching in combination with data fetching libraries, the default network mode is [online](#network-mode-online). ## Network Mode: online @@ -19,11 +19,11 @@ The flags `isFetching` and `isPaused` are derived from this state and exposed fo > Keep in mind that it might not be enough to check for `loading` state to show a loading spinner. Queries can be in `state: 'loading'`, but `fetchStatus: 'paused'` if they are mounting for the first time, and you have no network connection. -If a query runs because you are online, but you go offline while the fetch is still happening, React Query will also pause the retry mechanism. Paused queries will then continue to run once you re-gain network connection. This is independent of `refetchOnReconnect` (which also defaults to `true` in this mode), because it is not a `refetch`, but rather a `continue`. If the query has been [cancelled](../guides/query-cancellation) in the meantime, it will not continue. +If a query runs because you are online, but you go offline while the fetch is still happening, Tanstack Query will also pause the retry mechanism. Paused queries will then continue to run once you re-gain network connection. This is independent of `refetchOnReconnect` (which also defaults to `true` in this mode), because it is not a `refetch`, but rather a `continue`. If the query has been [cancelled](../guides/query-cancellation) in the meantime, it will not continue. ## Network Mode: always -In this mode, React Query will always fetch and ignore the online / offline state. This is likely the mode you want to choose if you use React Query in an environment where you don't need an active network connection for your Queries to work - e.g. if you just read from `AsyncStorage`, or if you just want to return `Promise.resolve(5)` from your `queryFn`. +In this mode, Tanstack Query will always fetch and ignore the online / offline state. This is likely the mode you want to choose if you use Tanstack Query in an environment where you don't need an active network connection for your Queries to work - e.g. if you just read from `AsyncStorage`, or if you just want to return `Promise.resolve(5)` from your `queryFn`. - Queries will never be `paused` because you have no network connection. - Retries will also not pause - your Query will go to `error` state if it fails. @@ -31,7 +31,7 @@ In this mode, React Query will always fetch and ignore the online / offline stat ## Network Mode: offlineFirst -This mode is the middle ground between the first two options, where React Query will run the `queryFn` once, but then pause retries. This is very handy if you have a serviceWorker that intercepts a request for caching like in an [offline-first PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers), or if you use HTTP caching via the [Cache-Control header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#the_cache-control_header). +This mode is the middle ground between the first two options, where Tanstack Query will run the `queryFn` once, but then pause retries. This is very handy if you have a serviceWorker that intercepts a request for caching like in an [offline-first PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers), or if you use HTTP caching via the [Cache-Control header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#the_cache-control_header). In those situations, the first fetch might succeed because it comes from an offline storage / cache. However, if there is a cache miss, the network request will go out and fail, in which case this mode behaves like an `online` query - pausing retries. diff --git a/docs/react/guides/optimistic-updates.md b/docs/react/guides/optimistic-updates.md index a8b96cabe8..59aee30807 100644 --- a/docs/react/guides/optimistic-updates.md +++ b/docs/react/guides/optimistic-updates.md @@ -9,13 +9,15 @@ To do this, `useMutation`'s `onMutate` handler option allows you to return a val ## Updating a list of todos when adding a new todo +[//]: # 'Example' + ```tsx const queryClient = useQueryClient() useMutation({ mutationFn: updateTodo, // When mutate is called: - onMutate: async newTodo => { + onMutate: async (newTodo) => { // Cancel any outgoing refetches // (so they don't overwrite our optimistic update) await queryClient.cancelQueries({ queryKey: ['todos'] }) @@ -24,7 +26,7 @@ useMutation({ const previousTodos = queryClient.getQueryData(['todos']) // Optimistically update to the new value - queryClient.setQueryData(['todos'], old => [...old, newTodo]) + queryClient.setQueryData(['todos'], (old) => [...old, newTodo]) // Return a context object with the snapshotted value return { previousTodos } @@ -41,13 +43,17 @@ useMutation({ }) ``` +[//]: # 'Example' + ## Updating a single todo +[//]: # 'Example2' + ```tsx useMutation({ mutationFn: updateTodo, // When mutate is called: - onMutate: async newTodo => { + onMutate: async (newTodo) => { // Cancel any outgoing refetches // (so they don't overwrite our optimistic update) await queryClient.cancelQueries({ queryKey: ['todos', newTodo.id] }) @@ -65,18 +71,22 @@ useMutation({ onError: (err, newTodo, context) => { queryClient.setQueryData( ['todos', context.newTodo.id], - context.previousTodo + context.previousTodo, ) }, // Always refetch after error or success: - onSettled: newTodo => { + onSettled: (newTodo) => { queryClient.invalidateQueries({ queryKey: ['todos', newTodo.id] }) }, }) ``` +[//]: # 'Example2' + You can also use the `onSettled` function in place of the separate `onError` and `onSuccess` handlers if you wish: +[//]: # 'Example3' + ```tsx useMutation({ mutationFn: updateTodo, @@ -88,3 +98,5 @@ useMutation({ }, }) ``` + +[//]: # 'Example3' diff --git a/docs/react/guides/paginated-queries.md b/docs/react/guides/paginated-queries.md index e5a3acbbfc..45066af302 100644 --- a/docs/react/guides/paginated-queries.md +++ b/docs/react/guides/paginated-queries.md @@ -3,20 +3,22 @@ id: paginated-queries title: Paginated / Lagged Queries --- -Rendering paginated data is a very common UI pattern and in React Query, it "just works" by including the page information in the query key: +Rendering paginated data is a very common UI pattern and in Tanstack Query, it "just works" by including the page information in the query key: +[//]: # 'Example' ```tsx const result = useQuery({ queryKey: ['projects', page], queryFn: fetchProjects }) ``` +[//]: # 'Example' However, if you run this simple example, you might notice something strange: **The UI jumps in and out of the `success` and `loading` states because each new page is treated like a brand new query.** -This experience is not optimal and unfortunately is how many tools today insist on working. But not React Query! As you may have guessed, React Query comes with an awesome feature called `keepPreviousData` that allows us to get around this. +This experience is not optimal and unfortunately is how many tools today insist on working. But not Tanstack Query! As you may have guessed, Tanstack Query comes with an awesome feature called `keepPreviousData` that allows us to get around this. ## Better Paginated Queries with `keepPreviousData` @@ -26,6 +28,7 @@ Consider the following example where we would ideally want to increment a pageIn - When the new data arrives, the previous `data` is seamlessly swapped to show the new data. - `isPreviousData` is made available to know what data the query is currently providing you +[//]: # 'Example2' ```tsx function Todos() { const [page, setPage] = React.useState(0) @@ -81,6 +84,7 @@ function Todos() { ) } ``` +[//]: # 'Example2' ## Lagging Infinite Query results with `keepPreviousData` diff --git a/docs/react/guides/parallel-queries.md b/docs/react/guides/parallel-queries.md index becf05625b..a54344c921 100644 --- a/docs/react/guides/parallel-queries.md +++ b/docs/react/guides/parallel-queries.md @@ -7,7 +7,9 @@ title: Parallel Queries ## Manual Parallel Queries -When the number of parallel queries does not change, there is **no extra effort** to use parallel queries. Just use any number of React Query's `useQuery` and `useInfiniteQuery` hooks side-by-side! +When the number of parallel queries does not change, there is **no extra effort** to use parallel queries. Just use any number of Tanstack Query's `useQuery` and `useInfiniteQuery` hooks side-by-side! + +[//]: # 'Example' ```tsx function App () { @@ -19,23 +21,32 @@ function App () { } ``` +[//]: # 'Example' +[//]: # 'Info' + > When using React Query in suspense mode, this pattern of parallelism does not work, since the first query would throw a promise internally and would suspend the component before the other queries run. To get around this, you'll either need to use the `useQueries` hook (which is suggested) or orchestrate your own parallelism with separate components for each `useQuery` instance (which is lame). +[//]: # 'Info' + ## Dynamic Parallel Queries with `useQueries` -If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, React Query provides a `useQueries` hook, which you can use to dynamically execute as many queries in parallel as you'd like. +If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, Tanstack Query provides a `useQueries` hook, which you can use to dynamically execute as many queries in parallel as you'd like. `useQueries` accepts an **options object** with a **queries key** whose value is an **array of query objects**. It returns an **array of query results**: +[//]: # 'Example2' + ```tsx function App({ users }) { const userQueries = useQueries({ - queries: users.map(user => { + queries: users.map((user) => { return { queryKey: ['user', user.id], queryFn: () => fetchUserById(user.id), } - }) + }), }) } ``` + +[//]: # 'Example2' diff --git a/docs/react/guides/placeholder-query-data.md b/docs/react/guides/placeholder-query-data.md index 0e985ce195..d847aa129b 100644 --- a/docs/react/guides/placeholder-query-data.md +++ b/docs/react/guides/placeholder-query-data.md @@ -18,6 +18,8 @@ There are a few ways to supply placeholder data for a query to the cache before ## Placeholder Data as a Value +[//]: # 'Example' + ```tsx function Todos() { const result = useQuery({ @@ -28,25 +30,35 @@ function Todos() { } ``` +[//]: # 'Example' +[//]: # 'Memoization' + ### Placeholder Data Memoization If the process for accessing a query's placeholder data is intensive or just not something you want to perform on every render, you can memoize the value: +[//]: # 'Memoization' +[//]: # 'Example2' + ```tsx function Todos() { const placeholderData = useMemo(() => generateFakeTodos(), []) const result = useQuery({ queyKey: ['todos'], queryFn: () => fetch('/todos'), - placeholderData + placeholderData, }) } ``` +[//]: # 'Example2' + ### Placeholder Data from Cache In some circumstances, you may be able to provide the placeholder data for a query from the cached result of another. A good example of this would be searching the cached data from a blog post list query for a preview version of the post, then using that as the placeholder data for your individual post query: +[//]: # 'Example3' + ```tsx function Todo({ blogPostId }) { const result = useQuery({ @@ -57,12 +69,17 @@ function Todo({ blogPostId }) { // query as the placeholder data for this blogPost query return queryClient .getQueryData(['blogPosts']) - ?.find(d => d.id === blogPostId) + ?.find((d) => d.id === blogPostId) }, }) } ``` +[//]: # 'Example3' +[//]: # 'Materials' + ## Further reading For a comparison between `Placeholder Data` and `Initial Data`, have a look at the [Community Resources](../community/tkdodos-blog#9-placeholder-and-initial-data-in-react-query). + +[//]: # 'Materials' diff --git a/docs/react/guides/prefetching.md b/docs/react/guides/prefetching.md index 390c048635..1217a9f068 100644 --- a/docs/react/guides/prefetching.md +++ b/docs/react/guides/prefetching.md @@ -5,6 +5,8 @@ title: Prefetching If you're lucky enough, you may know enough about what your users will do to be able to prefetch the data they need before it's needed! If this is the case, you can use the `prefetchQuery` method to prefetch the results of a query to be placed into the cache: +[//]: # 'Example' + ```tsx const prefetchTodos = async () => { // The results of this query will be cached like a normal query @@ -15,14 +17,20 @@ const prefetchTodos = async () => { } ``` +[//]: # 'Example' + - If data for this query is already in the cache and **not invalidated**, the data will not be fetched -- If a `staleTime` is passed eg. `prefetchQuery('todos', fn, { staleTime: 5000 })` and the data is older than the specified staleTime, the query will be fetched +- If a `staleTime` is passed eg. `prefetchQuery({queryKey: ['todos'], queryFn: fn, staleTime: 5000 })` and the data is older than the specified staleTime, the query will be fetched - If no instances of `useQuery` appear for a prefetched query, it will be deleted and garbage collected after the time specified in `cacheTime`. ## Manually Priming a Query Alternatively, if you already have the data for your query synchronously available, you don't need to prefetch it. You can just use the [Query Client's `setQueryData` method](../reference/QueryClient#queryclientsetquerydata) to directly add or update a query's cached result by key. +[//]: # 'Example2' + ```tsx queryClient.setQueryData(['todos'], todos) ``` + +[//]: # 'Example2' diff --git a/docs/react/guides/queries.md b/docs/react/guides/queries.md index abafbc643f..72a58dc341 100644 --- a/docs/react/guides/queries.md +++ b/docs/react/guides/queries.md @@ -14,6 +14,8 @@ To subscribe to a query in your components or custom hooks, call the `useQuery` - Resolves the data, or - Throws an error +[//]: # 'Example' + ```tsx import { useQuery } from '@tanstack/react-query' @@ -22,14 +24,20 @@ function App() { } ``` +[//]: # 'Example' + The **unique key** you provide is used internally for refetching, caching, and sharing your queries throughout your application. The query result returned by `useQuery` contains all of the information about the query that you'll need for templating and any other usage of the data: +[//]: # 'Example2' + ```tsx const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList }) ``` +[//]: # 'Example2' + The `result` object contains a few very important states you'll need to be aware of to be productive. A query can only be in one of the following states at any given moment: - `isLoading` or `status === 'loading'` - The query has no data yet @@ -43,6 +51,8 @@ Beyond those primary states, more information is available depending on the stat For **most** queries, it's usually sufficient to check for the `isLoading` state, then the `isError` state, then finally, assume that the data is available and render the successful state: +[//]: # 'Example3' + ```tsx function Todos() { const { isLoading, isError, data, error } = useQuery({ @@ -61,7 +71,7 @@ function Todos() { // We can assume by this point that `isSuccess === true` return (
    - {data.map(todo => ( + {data.map((todo) => (
  • {todo.title}
  • ))}
@@ -69,8 +79,12 @@ function Todos() { } ``` +[//]: # 'Example3' + If booleans aren't your thing, you can always use the `status` state as well: +[//]: # 'Example4' + ```tsx function Todos() { const { status, data, error } = useQuery({ @@ -89,7 +103,7 @@ function Todos() { // also status === 'success', but "else" logic works, too return (
    - {data.map(todo => ( + {data.map((todo) => (
  • {todo.title}
  • ))}
@@ -97,6 +111,8 @@ function Todos() { } ``` +[//]: # 'Example4' + TypeScript will also narrow the type of `data` correctly if you've checked for `loading` and `error` before accessing it. ### FetchStatus @@ -110,6 +126,7 @@ In addition to the `status` field, the `result` object, you will also get an add ### Why two different states? Background refetches and stale-while-revalidate logic make all combinations for `status` and `fetchStatus` possible. For example: + - a query in `success` status will usually be in `idle` fetchStatus, but it could also be in `fetching` if a background refetch is happening. - a query that mounts and has no data will usually be in `loading` status and `fetching` fetchStatus, but it could also be `paused` if there is no network connection. @@ -118,6 +135,10 @@ So keep in mind that a query can be in `loading` state without actually fetching - The `status` gives information about the `data`: Do we have any or not? - The `fetchStatus` gives information about the `queryFn`: Is it running or not? +[//]: # 'Materials' + ## Further Reading For an alternative way of performing status checks, have a look at the [Community Resources](../community/tkdodos-blog#4-status-checks-in-react-query). + +[//]: # 'Materials' diff --git a/docs/vue/guides/custom-client.md b/docs/vue/guides/custom-client.md index 0b3e6d19f9..bbbb507695 100644 --- a/docs/vue/guides/custom-client.md +++ b/docs/vue/guides/custom-client.md @@ -55,7 +55,11 @@ app.use(VueQueryPlugin, vueQueryPluginOptions) To use the custom client key, You have to provide it as a query options ```js -useQuery('query1', fetcher, { queryClientKey: 'foo' }) +useQuery({ + queryKey: ['query1'], + queryFn: fetcher, + queryClientKey: 'foo', +}) ``` Internally custom key will be combined with default query key as a suffix. But user do not have to worry about it. diff --git a/docs/vue/guides/mutations.md b/docs/vue/guides/mutations.md index d8d2a23bd5..38c30e3413 100644 --- a/docs/vue/guides/mutations.md +++ b/docs/vue/guides/mutations.md @@ -3,3 +3,95 @@ id: mutations title: Mutations ref: docs/react/guides/mutations.md --- + +[//]: # 'Example' + +```vue + + + +``` + +[//]: # 'Example' +[//]: # 'Info1' +[//]: # 'Info1' +[//]: # 'Example2' +[//]: # 'Example2' +[//]: # 'Example3' + +```vue + + + +``` + +[//]: # 'Example3' +[//]: # 'Example11' + +```js +const client = new QueryClient({ + defaultOptions: { + queries: { + cacheTime: 1000 * 60 * 60 * 24, // 24 hours + }, + }, +}) + +// we need a default mutation function so that paused mutations can resume after a page reload +queryClient.setMutationDefaults({ + mutationKey: ['todos'], + mutationFn: ({ id, data }) => { + return api.updateTodo(id, data) + }, +}) + +const vueQueryOptions: VueQueryPluginOptions = { + queryClient: client, + clientPersister: (queryClient) => { + return persistQueryClient({ + queryClient, + persister: createSyncStoragePersister({ storage: localStorage }), + }) + }, + clientPersisterOnSuccess: (queryClient) => { + queryClient.resumePausedMutations() + }, +} + +createApp(App).use(VueQueryPlugin, vueQueryOptions).mount('#app') +``` + +[//]: # 'Example11' +[//]: # 'Materials' +[//]: # 'Materials' diff --git a/docs/vue/guides/network-mode.md b/docs/vue/guides/network-mode.md new file mode 100644 index 0000000000..0882bf558b --- /dev/null +++ b/docs/vue/guides/network-mode.md @@ -0,0 +1,6 @@ +--- +id: network-mode +title: Network Mode +ref: docs/react/guides/network-mode.md +replace: { 'React Query': 'Vue Query' } +--- diff --git a/docs/vue/guides/optimistic-updates.md b/docs/vue/guides/optimistic-updates.md new file mode 100644 index 0000000000..0cb1926f0f --- /dev/null +++ b/docs/vue/guides/optimistic-updates.md @@ -0,0 +1,103 @@ +--- +id: optimistic-updates +title: Optimistic Updates +ref: docs/react/guides/optimistic-updates.md +--- + +When you optimistically update your state before performing a mutation, there is a chance that the mutation will fail. In most of these failure cases, you can just trigger a refetch for your optimistic queries to revert them to their true server state. In some circumstances though, refetching may not work correctly and the mutation error could represent some type of server issue that won't make it possible to refetch. In this event, you can instead choose to rollback your update. + +To do this, `useMutation`'s `onMutate` handler option allows you to return a value that will later be passed to both `onError` and `onSettled` handlers as the last argument. In most cases, it is most useful to pass a rollback function. + +## Updating a list of todos when adding a new todo + +[//]: # 'Example' + +```tsx +const queryClient = useQueryClient() + +useMutation({ + mutationFn: updateTodo, + // When mutate is called: + onMutate: async (newTodo) => { + // Cancel any outgoing refetches + // (so they don't overwrite our optimistic update) + await queryClient.cancelQueries({ queryKey: ['todos'] }) + + // Snapshot the previous value + const previousTodos = queryClient.getQueryData(['todos']) + + // Optimistically update to the new value + queryClient.setQueryData(['todos'], (old) => [...old, newTodo]) + + // Return a context object with the snapshotted value + return { previousTodos } + }, + // If the mutation fails, + // use the context returned from onMutate to roll back + onError: (err, newTodo, context) => { + queryClient.setQueryData(['todos'], context.previousTodos) + }, + // Always refetch after error or success: + onSettled: () => { + queryClient.invalidateQueries({ queryKey: ['todos'] }) + }, +}) +``` + +[//]: # 'Example' + +## Updating a single todo + +[//]: # 'Example2' + +```tsx +useMutation({ + mutationFn: updateTodo, + // When mutate is called: + onMutate: async (newTodo) => { + // Cancel any outgoing refetches + // (so they don't overwrite our optimistic update) + await queryClient.cancelQueries({ queryKey: ['todos', newTodo.id] }) + + // Snapshot the previous value + const previousTodo = queryClient.getQueryData(['todos', newTodo.id]) + + // Optimistically update to the new value + queryClient.setQueryData(['todos', newTodo.id], newTodo) + + // Return a context with the previous and new todo + return { previousTodo, newTodo } + }, + // If the mutation fails, use the context we returned above + onError: (err, newTodo, context) => { + queryClient.setQueryData( + ['todos', context.newTodo.id], + context.previousTodo, + ) + }, + // Always refetch after error or success: + onSettled: (newTodo) => { + queryClient.invalidateQueries({ queryKey: ['todos', newTodo.id] }) + }, +}) +``` + +[//]: # 'Example2' + +You can also use the `onSettled` function in place of the separate `onError` and `onSuccess` handlers if you wish: + +[//]: # 'Example3' + +```tsx +useMutation({ + mutationFn: updateTodo, + // ... + onSettled: (newTodo, error, variables, context) => { + if (error) { + // do something + } + }, +}) +``` + +[//]: # 'Example3' diff --git a/docs/vue/guides/paginated-queries.md b/docs/vue/guides/paginated-queries.md new file mode 100644 index 0000000000..620537a781 --- /dev/null +++ b/docs/vue/guides/paginated-queries.md @@ -0,0 +1,53 @@ +--- +id: paginated-queries +title: Paginated / Lagged Queries +ref: docs/react/guides/paginated-queries.md +--- + +[//]: # 'Example2' + +```vue + + + +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/parallel-queries.md b/docs/vue/guides/parallel-queries.md new file mode 100644 index 0000000000..98aad95152 --- /dev/null +++ b/docs/vue/guides/parallel-queries.md @@ -0,0 +1,38 @@ +--- +id: parallel-queries +title: Parallel Queries +ref: docs/react/guides/parallel-queries.md +--- + +[//]: # 'Example' + +```vue + +``` + +[//]: # 'Example' +[//]: # 'Info' +[//]: # 'Info' +[//]: # 'Example2' + +```js +const users = computed(...) +const queries = computed(() => users.value.map(user => { + return { + queryKey: ['user', user.id], + queryFn: () => fetchUserById(user.id), + } + }) +); +const userQueries = useQueries({queries: queries}) +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/placeholder-query-data.md b/docs/vue/guides/placeholder-query-data.md new file mode 100644 index 0000000000..6075f554c6 --- /dev/null +++ b/docs/vue/guides/placeholder-query-data.md @@ -0,0 +1,40 @@ +--- +id: placeholder-query-data +title: Placeholder Query Data +ref: docs/react/guides/placeholder-query-data.md +--- + +[//]: # 'Example' + +```tsx +const result = useQuery({ + queryKey: ['todos'], + queryFn: () => fetch('/todos'), + placeholderData: placeholderTodos, +}) +``` + +[//]: # 'Example' +[//]: # 'Memoization' +[//]: # 'Memoization' +[//]: # 'Example2' +[//]: # 'Example2' +[//]: # 'Example3' + +```tsx +const result = useQuery({ + queryKey: ['blogPost', blogPostId], + queryFn: () => fetch(`/blogPosts/${blogPostId}`), + placeholderData: () => { + // Use the smaller/preview version of the blogPost from the 'blogPosts' + // query as the placeholder data for this blogPost query + return queryClient + .getQueryData(['blogPosts']) + ?.find((d) => d.id === blogPostId) + }, +}) +``` + +[//]: # 'Example3' +[//]: # 'Materials' +[//]: # 'Materials' diff --git a/docs/vue/guides/prefetching.md b/docs/vue/guides/prefetching.md new file mode 100644 index 0000000000..b4e4f62020 --- /dev/null +++ b/docs/vue/guides/prefetching.md @@ -0,0 +1,5 @@ +--- +id: prefetching +title: Prefetching +ref: docs/react/guides/prefetching.md +--- diff --git a/docs/vue/guides/queries.md b/docs/vue/guides/queries.md new file mode 100644 index 0000000000..7d436f698f --- /dev/null +++ b/docs/vue/guides/queries.md @@ -0,0 +1,63 @@ +--- +id: queries +title: Queries +ref: docs/react/guides/queries.md +--- + +[//]: # 'Example' + +```ts +import { useQuery } from 'vue-query' + +const result = useQuery({ queryKey: ['todos'], queryFn: fetchTodoList }) +``` + +[//]: # 'Example' +[//]: # 'Example3' + +```vue + + + +``` + +[//]: # 'Example3' +[//]: # 'Example4' + +```vue + + + +``` + +[//]: # 'Example4' +[//]: # 'Materials' +[//]: # 'Materials' From 34aeba90eb2a53f0267027e907a69dc5d387072a Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Mon, 26 Dec 2022 17:58:11 +0100 Subject: [PATCH 4/7] docs: vue-query docs part 4 --- docs/config.json | 2 +- docs/react/guides/network-mode.md | 2 +- docs/react/guides/query-cancellation.md | 58 +++-- docs/react/guides/query-functions.md | 35 ++- docs/react/guides/query-invalidation.md | 30 ++- docs/react/guides/query-keys.md | 25 +- docs/react/guides/query-retries.md | 30 ++- docs/react/guides/scroll-restoration.md | 4 +- .../guides/updates-from-mutation-responses.md | 8 +- docs/react/guides/window-focus-refetching.md | 29 ++- .../guides/does-this-replace-client-state.md | 52 ---- docs/vue/guides/network-mode.md | 1 - docs/vue/guides/query-cancellation.md | 25 ++ docs/vue/guides/query-functions.md | 22 ++ docs/vue/guides/query-invalidation.md | 6 + docs/vue/guides/query-keys.md | 16 ++ docs/vue/guides/query-retries.md | 39 +++ docs/vue/guides/scroll-restoration.md | 5 + docs/vue/guides/ssr.md | 222 ++++++++++++++++++ docs/vue/guides/suspense.md | 54 +++++ docs/vue/guides/testing.md | 4 + .../guides/updates-from-mutation-responses.md | 5 + docs/vue/guides/window-focus-refetching.md | 25 ++ 23 files changed, 600 insertions(+), 99 deletions(-) create mode 100644 docs/vue/guides/query-cancellation.md create mode 100644 docs/vue/guides/query-functions.md create mode 100644 docs/vue/guides/query-invalidation.md create mode 100644 docs/vue/guides/query-keys.md create mode 100644 docs/vue/guides/query-retries.md create mode 100644 docs/vue/guides/scroll-restoration.md create mode 100644 docs/vue/guides/ssr.md create mode 100644 docs/vue/guides/suspense.md create mode 100644 docs/vue/guides/testing.md create mode 100644 docs/vue/guides/updates-from-mutation-responses.md create mode 100644 docs/vue/guides/window-focus-refetching.md diff --git a/docs/config.json b/docs/config.json index bfa23e981c..3c7b3ee29b 100644 --- a/docs/config.json +++ b/docs/config.json @@ -547,7 +547,7 @@ "to": "vue/guides/filters" }, { - "label": "SSR & Next.js", + "label": "SSR & Nuxt", "to": "vue/guides/ssr" }, { diff --git a/docs/react/guides/network-mode.md b/docs/react/guides/network-mode.md index be3987ee26..6cef69383d 100644 --- a/docs/react/guides/network-mode.md +++ b/docs/react/guides/network-mode.md @@ -37,7 +37,7 @@ In those situations, the first fetch might succeed because it comes from an offl ## Devtools -The [React Query Devtools](../devtools) will show Queries in a `paused` state if they would be fetching, but there is no network connection. There is also a toggle button to _Mock offline behavior_. Please note that this button will _not_ actually mess with your network connection (you can do that in the browser devtools), but it will set the [OnlineManager](../reference/onlineManager) in an offline state. +The [Tanstack Query Devtools](../devtools) will show Queries in a `paused` state if they would be fetching, but there is no network connection. There is also a toggle button to _Mock offline behavior_. Please note that this button will _not_ actually mess with your network connection (you can do that in the browser devtools), but it will set the [OnlineManager](../reference/onlineManager) in an offline state. ## Signature diff --git a/docs/react/guides/query-cancellation.md b/docs/react/guides/query-cancellation.md index 0cb91fb9c3..87504d2eed 100644 --- a/docs/react/guides/query-cancellation.md +++ b/docs/react/guides/query-cancellation.md @@ -3,7 +3,7 @@ id: query-cancellation title: Query Cancellation --- -React Query provides each query function with an [`AbortSignal` instance](https://developer.mozilla.org/docs/Web/API/AbortSignal), **if it's available in your runtime environment**. When a query becomes out-of-date or inactive, this `signal` will become aborted. This means that all queries are cancellable, and you can respond to the cancellation inside your query function if desired. The best part about this is that it allows you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation. Additionally, this solution works better with TypeScript than the old solution. +Tanstack Query provides each query function with an [`AbortSignal` instance](https://developer.mozilla.org/docs/Web/API/AbortSignal), **if it's available in your runtime environment**. When a query becomes out-of-date or inactive, this `signal` will become aborted. This means that all queries are cancellable, and you can respond to the cancellation inside your query function if desired. The best part about this is that it allows you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation. The `AbortController` API is available in [most runtime environments](https://developer.mozilla.org/docs/Web/API/AbortController#browser_compatibility), but if the runtime environment does not support it then the query function will receive `undefined` in its place. You may choose to polyfill the `AbortController` API if you wish, there are [several available](https://www.npmjs.com/search?q=abortcontroller%20polyfill). @@ -15,6 +15,8 @@ However, if you consume the `AbortSignal`, the Promise will be cancelled (e.g. a ## Using `fetch` +[//]: # 'Example' + ```tsx const query = useQuery({ queryKey: ['todos'], @@ -34,13 +36,15 @@ const query = useQuery({ }) return Promise.all(todoDetails) - } + }, }) ``` -## Using `axios` +[//]: # 'Example' + +## Using `axios` [v0.22.0+](https://github.com/axios/axios/releases/tag/v0.22.0) -### Using `axios` [v0.22.0+](https://github.com/axios/axios/releases/tag/v0.22.0) +[//]: # 'Example2' ```tsx import axios from 'axios' @@ -55,7 +59,11 @@ const query = useQuery({ }) ``` -### Using an `axios` version less than v0.22.0 +[//]: # 'Example2' + +### Using `axios` with version lower than v0.22.0 + +[//]: # 'Example3' ```tsx import axios from 'axios' @@ -72,18 +80,22 @@ const query = useQuery({ cancelToken: source.token, }) - // Cancel the request if React Query signals to abort + // Cancel the request if Tanstack Query signals to abort signal?.addEventListener('abort', () => { - source.cancel('Query was cancelled by React Query') + source.cancel('Query was cancelled by Tanstack Query') }) return promise - } + }, }) ``` +[//]: # 'Example3' + ## Using `XMLHttpRequest` +[//]: # 'Example4' + ```tsx const query = useQuery({ queryKey: ['todos'], @@ -100,14 +112,18 @@ const query = useQuery({ oReq.open('GET', '/todos') oReq.send() }) - } + }, }) ``` +[//]: # 'Example4' + ## Using `graphql-request` An `AbortSignal` can be set in the client `request` method. +[//]: # 'Example5' + ```tsx const client = new GraphQLClient(endpoint) @@ -115,29 +131,37 @@ const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { client.request({ document: query, signal }) - } + }, }) ``` -## Using `graphql-request` version less than v4.0.0 +[//]: # 'Example5' + +## Using `graphql-request` with version lower than v4.0.0 An `AbortSignal` can be set in the `GraphQLClient` constructor. +[//]: # 'Example6' + ```tsx const query = useQuery({ queryKey: ['todos'], queryFn: ({ signal }) => { const client = new GraphQLClient(endpoint, { - signal, - }); + signal, + }) return client.request(query, variables) - } + }, }) ``` +[//]: # 'Example6' + ## Manual Cancellation -You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call `queryClient.cancelQueries({ queryKey })`, which will cancel the query and revert it back to its previous state. If you have consumed the `signal` passed to the query function, React Query will additionally also cancel the Promise. +You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call `queryClient.cancelQueries({ queryKey })`, which will cancel the query and revert it back to its previous state. If you have consumed the `signal` passed to the query function, Tanstack Query will additionally also cancel the Promise. + +[//]: # 'Example7' ```tsx const query = useQuery({ @@ -145,7 +169,7 @@ const query = useQuery({ queryFn: async ({ signal }) => { const resp = await fetch('/todos', { signal }) return resp.json() - } + }, }) const queryClient = useQueryClient() @@ -161,3 +185,5 @@ return ( ) ``` + +[//]: # 'Example7' diff --git a/docs/react/guides/query-functions.md b/docs/react/guides/query-functions.md index 873ec025c1..04e52a5c7e 100644 --- a/docs/react/guides/query-functions.md +++ b/docs/react/guides/query-functions.md @@ -7,22 +7,31 @@ A query function can be literally any function that **returns a promise**. The p All of the following are valid query function configurations: +[//]: # 'Example' + ```tsx useQuery({ queryKey: ['todos'], queryFn: fetchAllTodos }) useQuery({ queryKey: ['todos', todoId], queryFn: () => fetchTodoById(todoId) }) -useQuery({ queryKey: ['todos', todoId], queryFn: async () => { - const data = await fetchTodoById(todoId) - return data -}}) +useQuery({ + queryKey: ['todos', todoId], + queryFn: async () => { + const data = await fetchTodoById(todoId) + return data + }, +}) useQuery({ queryKey: ['todos', todoId], queryFn: ({ queryKey }) => fetchTodoById(queryKey[1]), }) ``` +[//]: # 'Example' + ## Handling and Throwing Errors -For React Query to determine a query has errored, the query function **must throw** or return a **rejected Promise**. Any error that is thrown in the query function will be persisted on the `error` state of the query. +For Tanstack Query to determine a query has errored, the query function **must throw** or return a **rejected Promise**. Any error that is thrown in the query function will be persisted on the `error` state of the query. + +[//]: # 'Example2' ```tsx const { error } = useQuery({ @@ -36,14 +45,18 @@ const { error } = useQuery({ } return data - } + }, }) ``` +[//]: # 'Example2' + ## Usage with `fetch` and other clients that do not throw by default While most utilities like `axios` or `graphql-request` automatically throw errors for unsuccessful HTTP calls, some utilities like `fetch` do not throw errors by default. If that's the case, you'll need to throw them on your own. Here is a simple way to do that with the popular `fetch` API: +[//]: # 'Example3' + ```tsx useQuery({ queryKey: ['todos', todoId], @@ -53,14 +66,18 @@ useQuery({ throw new Error('Network response was not ok') } return response.json() - } + }, }) ``` +[//]: # 'Example3' + ## Query Function Variables Query keys are not just for uniquely identifying the data you are fetching, but are also conveniently passed into your query function as part of the QueryFunctionContext. While not always necessary, this makes it possible to extract your query functions if needed: +[//]: # 'Example4' + ```tsx function Todos({ status, page }) { const result = useQuery({ @@ -76,6 +93,8 @@ function fetchTodoList({ queryKey }) { } ``` +[//]: # 'Example4' + ### QueryFunctionContext The `QueryFunctionContext` is the object passed to each query function. It consists of: @@ -85,7 +104,7 @@ The `QueryFunctionContext` is the object passed to each query function. It consi - only for [Infinite Queries](../guides/infinite-queries) - the page parameter used to fetch the current page - `signal?: AbortSignal` - - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance provided by react-query + - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance provided by Tanstack Query - Can be used for [Query Cancellation](../guides/query-cancellation) - `meta: Record | undefined` - an optional field you can fill with additional information about your query diff --git a/docs/react/guides/query-invalidation.md b/docs/react/guides/query-invalidation.md index 0d8aac55bc..73b1c026cf 100644 --- a/docs/react/guides/query-invalidation.md +++ b/docs/react/guides/query-invalidation.md @@ -5,6 +5,8 @@ title: Query Invalidation Waiting for queries to become stale before they are fetched again doesn't always work, especially when you know for a fact that a query's data is out of date because of something the user has done. For that purpose, the `QueryClient` has an `invalidateQueries` method that lets you intelligently mark queries as stale and potentially refetch them too! +[//]: # 'Example' + ```tsx // Invalidate every query in the cache queryClient.invalidateQueries() @@ -12,7 +14,9 @@ queryClient.invalidateQueries() queryClient.invalidateQueries({ queryKey: ['todos'] }) ``` -> Note: Where other libraries that use normalized caches would attempt to update local queries with the new data either imperatively or via schema inference, React Query gives you the tools to avoid the manual labor that comes with maintaining normalized caches and instead prescribes **targeted invalidation, background-refetching and ultimately atomic updates**. +[//]: # 'Example' + +> Note: Where other libraries that use normalized caches would attempt to update local queries with the new data either imperatively or via schema inference, Tanstack Query gives you the tools to avoid the manual labor that comes with maintaining normalized caches and instead prescribes **targeted invalidation, background-refetching and ultimately atomic updates**. When a query is invalidated with `invalidateQueries`, two things happen: @@ -25,6 +29,8 @@ When using APIs like `invalidateQueries` and `removeQueries` (and others that su In this example, we can use the `todos` prefix to invalidate any queries that start with `todos` in their query key: +[//]: # 'Example2' + ```tsx import { useQuery, useQueryClient } from '@tanstack/react-query' @@ -44,8 +50,12 @@ const todoListQuery = useQuery({ }) ``` +[//]: # 'Example2' + You can even invalidate queries with specific variables by passing a more specific query key to the `invalidateQueries` method: +[//]: # 'Example3' + ```tsx queryClient.invalidateQueries({ queryKey: ['todos', { type: 'done' }], @@ -64,8 +74,12 @@ const todoListQuery = useQuery({ }) ``` +[//]: # 'Example3' + The `invalidateQueries` API is very flexible, so even if you want to **only** invalidate `todos` queries that don't have any more variables or subkeys, you can pass an `exact: true` option to the `invalidateQueries` method: +[//]: # 'Example4' + ```tsx queryClient.invalidateQueries({ queryKey: ['todos'], @@ -85,11 +99,15 @@ const todoListQuery = useQuery({ }) ``` +[//]: # 'Example4' + If you find yourself wanting **even more** granularity, you can pass a predicate function to the `invalidateQueries` method. This function will receive each `Query` instance from the query cache and allow you to return `true` or `false` for whether you want to invalidate that query: +[//]: # 'Example5' + ```tsx queryClient.invalidateQueries({ - predicate: query => + predicate: (query) => query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10, }) @@ -97,17 +115,19 @@ queryClient.invalidateQueries({ const todoListQuery = useQuery({ queryKey: ['todos', { version: 20 }], queryFn: fetchTodoList, -}), +}) // The query below will be invalidated const todoListQuery = useQuery({ queryKey: ['todos', { version: 10 }], queryFn: fetchTodoList, -}), +}) // However, the following query below will NOT be invalidated const todoListQuery = useQuery({ queryKey: ['todos', { version: 5 }], queryFn: fetchTodoList, -}), +}) ``` + +[//]: # 'Example5' diff --git a/docs/react/guides/query-keys.md b/docs/react/guides/query-keys.md index 7e800c0bf6..4c75ce3abc 100644 --- a/docs/react/guides/query-keys.md +++ b/docs/react/guides/query-keys.md @@ -3,7 +3,7 @@ id: query-keys title: Query Keys --- -At its core, React Query manages query caching for you based on query keys. Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. As long as the query key is serializable, and **unique to the query's data**, you can use it! +At its core, Tanstack Query manages query caching for you based on query keys. Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. As long as the query key is serializable, and **unique to the query's data**, you can use it! ## Simple Query Keys @@ -12,6 +12,8 @@ The simplest form of a key is an array with constants values. This format is use - Generic List/Index resources - Non-hierarchical resources +[//]: # 'Example' + ```tsx // A list of todos useQuery({ queryKey: ['todos'], ... }) @@ -20,6 +22,8 @@ useQuery({ queryKey: ['todos'], ... }) useQuery({ queryKey: ['something', 'special'], ... }) ``` +[//]: # 'Example' + ## Array Keys with variables When a query needs more information to uniquely describe its data, you can use an array with a string and any number of serializable objects to describe it. This is useful for: @@ -29,6 +33,8 @@ When a query needs more information to uniquely describe its data, you can use a - Queries with additional parameters - It's common to pass an object of additional options +[//]: # 'Example2' + ```tsx // An individual todo useQuery({ queryKey: ['todo', 5], ... }) @@ -40,28 +46,40 @@ useQuery({ queryKey: ['todo', 5, { preview: true }], ...}) useQuery({ queryKey: ['todos', { type: 'done' }], ... }) ``` +[//]: # 'Example2' + ## Query Keys are hashed deterministically! This means that no matter the order of keys in objects, all of the following queries are considered equal: +[//]: # 'Example3' + ```tsx useQuery({ queryKey: ['todos', { status, page }], ... }) useQuery({ queryKey: ['todos', { page, status }], ...}) useQuery({ queryKey: ['todos', { page, status, other: undefined }], ... }) ``` +[//]: # 'Example3' + The following query keys, however, are not equal. Array item order matters! +[//]: # 'Example4' + ```tsx useQuery({ queryKey: ['todos', status, page], ... }) useQuery({ queryKey: ['todos', page, status], ...}) useQuery({ queryKey: ['todos', undefined, page, status], ...}) ``` +[//]: # 'Example4' + ## If your query function depends on a variable, include it in your query key Since query keys uniquely describe the data they are fetching, they should include any variables you use in your query function that **change**. For example: +[//]: # 'Example5' + ```tsx function Todos({ todoId }) { const result = useQuery({ @@ -71,7 +89,12 @@ function Todos({ todoId }) { } ``` +[//]: # 'Example5' +[//]: # 'Materials' + ## Further reading For tips on organizing Query Keys in larger applications, have a look at [Effective React Query Keys](../community/tkdodos-blog#8-effective-react-query-keys) and check the [Query Key Factory Package](../community/lukemorales-query-key-factory) from the Community Resources. + +[//]: # 'Materials' diff --git a/docs/react/guides/query-retries.md b/docs/react/guides/query-retries.md index d6d890641f..87876579b8 100644 --- a/docs/react/guides/query-retries.md +++ b/docs/react/guides/query-retries.md @@ -3,7 +3,7 @@ id: query-retries title: Query Retries --- -When a `useQuery` query fails (the query function throws an error), React Query will automatically retry the query if that query's request has not reached the max number of consecutive retries (defaults to `3`) or a function is provided to determine if a retry is allowed. +When a `useQuery` query fails (the query function throws an error), Tanstack Query will automatically retry the query if that query's request has not reached the max number of consecutive retries (defaults to `3`) or a function is provided to determine if a retry is allowed. You can configure retries both on a global level and an individual query level. @@ -12,31 +12,41 @@ You can configure retries both on a global level and an individual query level. - Setting `retry = true` will infinitely retry failing requests. - Setting `retry = (failureCount, error) => ...` allows for custom logic based on why the request failed. +[//]: # 'Example' + ```tsx import { useQuery } from '@tanstack/react-query' // Make a specific query retry a certain number of times const result = useQuery({ - queryKey: ['todos', 1], - queryFn: fetchTodoListPage, - retry: 10, // Will retry failed requests 10 times before displaying an error + queryKey: ['todos', 1], + queryFn: fetchTodoListPage, + retry: 10, // Will retry failed requests 10 times before displaying an error }) ``` +[//]: # 'Example' + ## Retry Delay -By default, retries in React Query do not happen immediately after a request fails. As is standard, a back-off delay is gradually applied to each retry attempt. +By default, retries in Tanstack Query do not happen immediately after a request fails. As is standard, a back-off delay is gradually applied to each retry attempt. The default `retryDelay` is set to double (starting at `1000`ms) with each attempt, but not exceed 30 seconds: +[//]: # 'Example2' + ```tsx // Configure for all queries -import { QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { + QueryCache, + QueryClient, + QueryClientProvider, +} from '@tanstack/react-query' const queryClient = new QueryClient({ defaultOptions: { queries: { - retryDelay: attemptIndex => Math.min(1000 * 2 ** attemptIndex, 30000), + retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), }, }, }) @@ -46,8 +56,12 @@ function App() { } ``` +[//]: # 'Example2' + Though it is not recommended, you can obviously override the `retryDelay` function/integer in both the Provider and individual query options. If set to an integer instead of a function the delay will always be the same amount of time: +[//]: # 'Example3' + ```tsx const result = useQuery({ queryKey: ['todos'], @@ -55,3 +69,5 @@ const result = useQuery({ retryDelay: 1000, // Will always wait 1000ms to retry, regardless of how many retries }) ``` + +[//]: # 'Example3' diff --git a/docs/react/guides/scroll-restoration.md b/docs/react/guides/scroll-restoration.md index ddc3819b66..288688d233 100644 --- a/docs/react/guides/scroll-restoration.md +++ b/docs/react/guides/scroll-restoration.md @@ -3,6 +3,6 @@ id: scroll-restoration title: Scroll Restoration --- -Traditionally, when you navigate to a previously visited page on a web browser, you would find that the page would be scrolled to the exact position where you were before you navigated away from that page. This is called **scroll restoration** and has been in a bit of a regression since web applications have started moving towards client side data fetching. With React Query however, that's no longer the case. +Traditionally, when you navigate to a previously visited page on a web browser, you would find that the page would be scrolled to the exact position where you were before you navigated away from that page. This is called **scroll restoration** and has been in a bit of a regression since web applications have started moving towards client side data fetching. With Tanstack Query however, that's no longer the case. -Out of the box, "scroll restoration" for all queries (including paginated and infinite queries) Just Works™️ in React Query. The reason for this is that query results are cached and able to be retrieved synchronously when a query is rendered. As long as your queries are being cached long enough (the default time is 5 minutes) and have not been garbage collected, scroll restoration will work out of the box all the time. +Out of the box, "scroll restoration" for all queries (including paginated and infinite queries) Just Works™️ in Tanstack Query. The reason for this is that query results are cached and able to be retrieved synchronously when a query is rendered. As long as your queries are being cached long enough (the default time is 5 minutes) and have not been garbage collected, scroll restoration will work out of the box all the time. diff --git a/docs/react/guides/updates-from-mutation-responses.md b/docs/react/guides/updates-from-mutation-responses.md index 850262830b..901c5a38ff 100644 --- a/docs/react/guides/updates-from-mutation-responses.md +++ b/docs/react/guides/updates-from-mutation-responses.md @@ -5,6 +5,7 @@ title: Updates from Mutation Responses When dealing with mutations that **update** objects on the server, it's common for the new object to be automatically returned in the response of the mutation. Instead of refetching any queries for that item and wasting a network call for data we already have, we can take advantage of the object returned by the mutation function and update the existing query with the new data immediately using the [Query Client's `setQueryData`](../reference/QueryClient#queryclientsetquerydata) method: +[//]: # 'Example' ```tsx const queryClient = useQueryClient() @@ -27,10 +28,12 @@ const { status, data, error } = useQuery({ queryFn: fetchTodoById, }) ``` +[//]: # 'Example' You might want to tie the `onSuccess` logic into a reusable mutation, for that you can create a custom hook like this: +[//]: # 'Example2' ```tsx const useMutateTodo = () => { const queryClient = useQueryClient() @@ -44,11 +47,13 @@ const useMutateTodo = () => { }) } ``` +[//]: # 'Example2' ## Immutability Updates via `setQueryData` must be performed in an _immutable_ way. **DO NOT** attempt to write directly to the cache by mutating data (that you retrieved via from the cache) in place. It might work at first but can lead to subtle bugs along the way. +[//]: # 'Example3' ```tsx queryClient.setQueryData( ['posts', { id }], @@ -59,9 +64,7 @@ queryClient.setQueryData( } return oldData }) -``` -```tsx queryClient.setQueryData( ['posts', { id }], // ✅ this is the way @@ -71,3 +74,4 @@ queryClient.setQueryData( } : oldData ) ``` +[//]: # 'Example3' diff --git a/docs/react/guides/window-focus-refetching.md b/docs/react/guides/window-focus-refetching.md index 22a25106be..0e6da62941 100644 --- a/docs/react/guides/window-focus-refetching.md +++ b/docs/react/guides/window-focus-refetching.md @@ -3,10 +3,12 @@ id: window-focus-refetching title: Window Focus Refetching --- -If a user leaves your application and returns to stale data, **React Query automatically requests fresh data for you in the background**. You can disable this globally or per-query using the `refetchOnWindowFocus` option: +If a user leaves your application and returns to stale data, **Tanstack Query automatically requests fresh data for you in the background**. You can disable this globally or per-query using the `refetchOnWindowFocus` option: #### Disabling Globally +[//]: # 'Example' + ```tsx // const queryClient = new QueryClient({ @@ -22,8 +24,12 @@ function App() { } ``` +[//]: # 'Example' + #### Disabling Per-Query +[//]: # 'Example2' + ```tsx useQuery({ queryKey: ['todos'], @@ -32,12 +38,16 @@ useQuery({ }) ``` +[//]: # 'Example2' + ## Custom Window Focus Event -In rare circumstances, you may want to manage your own window focus events that trigger React Query to revalidate. To do this, React Query provides a `focusManager.setEventListener` function that supplies you the callback that should be fired when the window is focused and allows you to set up your own events. When calling `focusManager.setEventListener`, the previously set handler is removed (which in most cases will be the default handler) and your new handler is used instead. For example, this is the default handler: +In rare circumstances, you may want to manage your own window focus events that trigger Tanstack Query to revalidate. To do this, Tanstack Query provides a `focusManager.setEventListener` function that supplies you the callback that should be fired when the window is focused and allows you to set up your own events. When calling `focusManager.setEventListener`, the previously set handler is removed (which in most cases will be the default handler) and your new handler is used instead. For example, this is the default handler: + +[//]: # 'Example3' ```tsx -focusManager.setEventListener(handleFocus => { +focusManager.setEventListener((handleFocus) => { // Listen to visibilitychange and focus if (typeof window !== 'undefined' && window.addEventListener) { window.addEventListener('visibilitychange', handleFocus, false) @@ -52,10 +62,14 @@ focusManager.setEventListener(handleFocus => { }) ``` +[//]: # 'Example3' + ## Ignoring Iframe Focus Events A great use-case for replacing the focus handler is that of iframe events. Iframes present problems with detecting window focus by both double-firing events and also firing false-positive events when focusing or using iframes within your app. If you experience this, you should use an event handler that ignores these events as much as possible. I recommend [this one](https://gist.github.com/tannerlinsley/1d3a2122332107fcd8c9cc379be10d88)! It can be set up in the following way: +[//]: # 'Example4' + ```tsx import { focusManager } from '@tanstack/react-query' import onWindowFocus from './onWindowFocus' // The gist above @@ -63,6 +77,9 @@ import onWindowFocus from './onWindowFocus' // The gist above focusManager.setEventListener(onWindowFocus) // Boom! ``` +[//]: # 'Example4' +[//]: # 'ReactNative' + ## Managing Focus in React Native Instead of event listeners on `window`, React Native provides focus information through the [`AppState` module](https://reactnative.dev/docs/appstate#app-states). You can use the `AppState` "change" event to trigger an update when the app state changes to "active": @@ -84,8 +101,12 @@ useEffect(() => { }, []) ``` +[//]: # 'ReactNative' + ## Managing focus state +[//]: # 'Example5' + ```tsx import { focusManager } from '@tanstack/react-query' @@ -96,6 +117,8 @@ focusManager.setFocused(true) focusManager.setFocused(undefined) ``` +[//]: # 'Example5' + ## Pitfalls & Caveats Some browser internal dialogue windows, such as spawned by `alert()` or file upload dialogues (as created by ``) might also trigger focus refetching after they close. This can result in unwanted side effects, as the refetching might trigger component unmounts or remounts before your file upload handler is executed. See [this issue on GitHub](https://github.com/tannerlinsley/react-query/issues/2960) for background and possible workarounds. diff --git a/docs/vue/guides/does-this-replace-client-state.md b/docs/vue/guides/does-this-replace-client-state.md index 63d8ff8937..a62cecefef 100644 --- a/docs/vue/guides/does-this-replace-client-state.md +++ b/docs/vue/guides/does-this-replace-client-state.md @@ -5,55 +5,3 @@ ref: docs/react/guides/does-this-replace-client-state.md replace: { 'Redux, MobX': 'Vuex, Pinia' } --- - -Well, let's start with a few important items: - -- React Query is a **server-state** library, responsible for managing asynchronous operations between your server and client -- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like React Query_ - -With those points in mind, the short answer is that React Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** - -For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to React Query is usually very tiny. - -> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **React Query is not a replacement for local/client state management**. However, you can use React Query along side most client state managers with zero issues. - -## A Contrived Example - -Here we have some "global" state being managed by a global state library: - -```tsx -const globalState = { - projects, - teams, - tasks, - users, - themeMode, - sidebarStatus, -} -``` - -Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to React Query, our remaining global state would look more like this: - -```tsx -const globalState = { - themeMode, - sidebarStatus, -} -``` - -This also means that with a few hook calls to `useQuery` and `useMutation`, we also get to remove any boilerplate code that was used to manage our server state eg. - -- Connectors -- Action Creators -- Middlewares -- Reducers -- Loading/Error/Result states -- Contexts - -With all of those things removed, you may ask yourself, **"Is it worth it to keep using our client state manager for this tiny global state?"** - -**And that's up to you!** - -But React Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. - -What are you waiting for, give it a go already! diff --git a/docs/vue/guides/network-mode.md b/docs/vue/guides/network-mode.md index 0882bf558b..a8cd44e244 100644 --- a/docs/vue/guides/network-mode.md +++ b/docs/vue/guides/network-mode.md @@ -2,5 +2,4 @@ id: network-mode title: Network Mode ref: docs/react/guides/network-mode.md -replace: { 'React Query': 'Vue Query' } --- diff --git a/docs/vue/guides/query-cancellation.md b/docs/vue/guides/query-cancellation.md new file mode 100644 index 0000000000..7b1ed7039f --- /dev/null +++ b/docs/vue/guides/query-cancellation.md @@ -0,0 +1,25 @@ +--- +id: query-cancellation +title: Query Cancellation +ref: docs/react/guides/query-cancellation.md +--- + +[//]: # 'Example7' + +```ts +const query = useQuery({ + queryKey: ['todos'], + queryFn: async ({ signal }) => { + const resp = await fetch('/todos', { signal }) + return resp.json() + }, +}) + +const queryClient = useQueryClient() + +function onButtonClick() { + queryClient.cancelQueries({ queryKey: ['todos'] }) +} +``` + +[//]: # 'Example7' diff --git a/docs/vue/guides/query-functions.md b/docs/vue/guides/query-functions.md new file mode 100644 index 0000000000..f13d03b090 --- /dev/null +++ b/docs/vue/guides/query-functions.md @@ -0,0 +1,22 @@ +--- +id: query-functions +title: Query Functions +ref: docs/react/guides/query-functions.md +--- + +[//]: # 'Example4' + +```js +const result = useQuery({ + queryKey: ['todos', { status, page }], + queryFn: fetchTodoList, +}) + +// Access the key, status and page variables in your query function! +function fetchTodoList({ queryKey }) { + const [_key, { status, page }] = queryKey + return new Promise() +} +``` + +[//]: # 'Example4' diff --git a/docs/vue/guides/query-invalidation.md b/docs/vue/guides/query-invalidation.md new file mode 100644 index 0000000000..cc0e6605a9 --- /dev/null +++ b/docs/vue/guides/query-invalidation.md @@ -0,0 +1,6 @@ +--- +id: query-invalidation +title: Query Invalidation +ref: docs/react/guides/query-invalidation.md +replace: { 'react-query': 'vue-query' } +--- diff --git a/docs/vue/guides/query-keys.md b/docs/vue/guides/query-keys.md new file mode 100644 index 0000000000..7c328adbb2 --- /dev/null +++ b/docs/vue/guides/query-keys.md @@ -0,0 +1,16 @@ +--- +id: query-keys +title: Query Keys +ref: docs/react/guides/query-keys.md +--- + +[//]: # 'Example5' + +```js +function useTodos(todoId) { + const queryKey = ['todos', todoId] + return useQuery(queryKey, () => fetchTodoById(todoId.value)) +} +``` + +[//]: # 'Example5' diff --git a/docs/vue/guides/query-retries.md b/docs/vue/guides/query-retries.md new file mode 100644 index 0000000000..e18c3f570d --- /dev/null +++ b/docs/vue/guides/query-retries.md @@ -0,0 +1,39 @@ +--- +id: query-retries +title: Query Retries +ref: docs/react/guides/query-retries.md +replace: { 'Provider': 'Plugin' } +--- + +[//]: # 'Example' + +```tsx +import { useQuery } from '@tanstack/vue-query' + +// Make a specific query retry a certain number of times +const result = useQuery({ + queryKey: ['todos', 1], + queryFn: fetchTodoListPage, + retry: 10, // Will retry failed requests 10 times before displaying an error +}) +``` + +[//]: # 'Example' +[//]: # 'Example2' + +```ts +import { VueQueryPlugin } from '@tanstack/vue-query' + +const vueQueryPluginOptions = { + queryClientConfig: { + defaultOptions: { + queries: { + retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), + }, + }, + }, +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +[//]: # 'Example2' diff --git a/docs/vue/guides/scroll-restoration.md b/docs/vue/guides/scroll-restoration.md new file mode 100644 index 0000000000..971ee8ff40 --- /dev/null +++ b/docs/vue/guides/scroll-restoration.md @@ -0,0 +1,5 @@ +--- +id: scroll-restoration +title: Scroll Restoration +ref: docs/react/guides/scroll-restoration.md +--- diff --git a/docs/vue/guides/ssr.md b/docs/vue/guides/ssr.md new file mode 100644 index 0000000000..9b2edcb356 --- /dev/null +++ b/docs/vue/guides/ssr.md @@ -0,0 +1,222 @@ +--- +id: ssr +title: SSR +--- + +Vue Query supports prefetching multiple queries on the server and then _dehydrating_ those queries to the queryClient. This means the server can prerender markup that is immediately available on page load and as soon as JS is available, Vue Query can upgrade or _hydrate_ those queries with the full functionality of the library. This includes refetching those queries on the client if they have become stale since the time they were rendered on the server. + +## Using Nuxt.js + +### Nuxt 3 + +First create `vue-query.ts` file in your `plugins` directory with the following content: + +```ts +import type { DehydratedState, VueQueryPluginOptions } from 'vue-query' +import { VueQueryPlugin, QueryClient, hydrate, dehydrate } from 'vue-query' +// Nuxt 3 app aliases +import { useState } from '#app' + +export default defineNuxtPlugin((nuxt) => { + const vueQueryState = useState('vue-query') + + // Modify your Vue Query global settings here + const queryClient = new QueryClient({ + defaultOptions: { queries: { staleTime: 5000 } }, + }) + const options: VueQueryPluginOptions = { queryClient } + + nuxt.vueApp.use(VueQueryPlugin, options) + + if (process.server) { + nuxt.hooks.hook('app:rendered', () => { + vueQueryState.value = dehydrate(queryClient) + }) + } + + if (process.client) { + nuxt.hooks.hook('app:created', () => { + hydrate(queryClient, vueQueryState.value) + }) + } +}) +``` + +Now you are ready to prefetch some data in your pages with `onServerPrefetch`. + +- Prefetch all the queries that you need with `queryClient.prefetchQuery` or `suspense` + +```ts +export default defineComponent({ + setup() { + const { data, suspense } = useQuery('test', fetcher) + + onServerPrefetch(async () => { + await suspense() + }) + + return { data } + }, +}) +``` + +### Nuxt 2 + +First create `vue-query.js` file in your `plugins` directory with the following content: + +```js +import Vue from 'vue' +import { VueQueryPlugin, QueryClient, hydrate } from 'vue-query' + +export default (context) => { + // Modify your Vue Query global settings here + const queryClient = new QueryClient({ + defaultOptions: { queries: { staleTime: 5000 } }, + }) + const options = { queryClient } + + Vue.use(VueQueryPlugin, options) + + if (process.client) { + if (context.nuxtState && context.nuxtState['vue-query']) { + hydrate(queryClient, context.nuxtState['vue-query']) + } + } +} +``` + +Add this plugin to your `nuxt.config.js` + +```js +module.exports = { + ... + plugins: ['~/plugins/vue-query.js'], +}; +``` + +Now you are ready to prefetch some data in your pages with `onServerPrefetch`. + +- Use `useContext` to get nuxt context +- Use `useQueryClient` to get server-side instance of `queryClient` +- Prefetch all the queries that you need with `queryClient.prefetchQuery` or `suspense` +- Dehydrate `queryClient` to the `nuxtContext` + +```js +// pages/todos.vue + + + +``` + +As demonstrated, it's fine to prefetch some queries and let others fetch on the queryClient. This means you can control what content server renders or not by adding or removing `prefetchQuery` or `suspense` for a specific query. + +## Using Vite SSR + +Sync VueQuery client state with [vite-ssr](https://github.com/frandiox/vite-ssr) in order to serialize it in the DOM: + +```js +// main.js (entry point) +import App from './App.vue' +import viteSSR from 'vite-ssr/vue' +import { QueryClient, VueQueryPlugin, hydrate, dehydrate } from 'vue-query' + +export default viteSSR(App, { routes: [] }, ({ app, initialState }) => { + // -- This is Vite SSR main hook, which is called once per request + + // Create a fresh VueQuery client + const queryClient = new QueryClient() + + // Sync initialState with the client state + if (import.meta.env.SSR) { + // Indicate how to access and serialize VueQuery state during SSR + initialState.vueQueryState = { toJSON: () => dehydrate(queryClient) } + } else { + // Reuse the existing state in the browser + hydrate(queryClient, initialState.vueQueryState) + } + + // Mount and provide the client to the app components + app.use(VueQueryPlugin, { queryClient }) +}) +``` + +Then, call VueQuery from any component using Vue's `onServerPrefetch`: + +```html + + + + +``` + +## Tips, Tricks and Caveats + +### Only successful queries are included in dehydration + +Any query with an error is automatically excluded from dehydration. This means that the default behavior is to pretend these queries were never loaded on the server, usually showing a loading state instead, and retrying the queries on the queryClient. This happens regardless of error. + +Sometimes this behavior is not desirable, maybe you want to render an error page with a correct status code instead on certain errors or queries. In those cases, use `fetchQuery` and catch any errors to handle those manually. + +### Staleness is measured from when the query was fetched on the server + +A query is considered stale depending on when it was `dataUpdatedAt`. A caveat here is that the server needs to have the correct time for this to work properly, but UTC time is used, so timezones do not factor into this. + +Because `staleTime` defaults to `0`, queries will be refetched in the background on page load by default. You might want to use a higher `staleTime` to avoid this double fetching, especially if you don't cache your markup. + +This refetching of stale queries is a perfect match when caching markup in a CDN! You can set the cache time of the page itself decently high to avoid having to re-render pages on the server, but configure the `staleTime` of the queries lower to make sure data is refetched in the background as soon as a user visits the page. Maybe you want to cache the pages for a week, but refetch the data automatically on page load if it's older than a day? + +### High memory consumption on server + +In case you are creating the `QueryClient` for every request, Vue Query creates the isolated cache for this client, which is preserved in memory for the `cacheTime` period. That may lead to high memory consumption on server in case of high number of requests during that period. + +On the server, `cacheTime` defaults to `Infinity` which disables manual garbage collection and will automatically clear memory once a request has finished. If you are explicitly setting a non-Infinity `cacheTime` then you will be responsible for clearing the cache early. + +To clear the cache after it is not needed and to lower memory consumption, you can add a call to [`queryClient.clear()`](../reference/QueryClient#queryclientclear) after the request is handled and dehydrated state has been sent to the client. + +Alternatively, you can set a smaller `cacheTime`. diff --git a/docs/vue/guides/suspense.md b/docs/vue/guides/suspense.md new file mode 100644 index 0000000000..ffa7be644f --- /dev/null +++ b/docs/vue/guides/suspense.md @@ -0,0 +1,54 @@ +--- +id: suspense +title: Suspense (experimental) +--- + +> NOTE: Suspense mode for Vue Query is experimental, same as Vue's Suspense itself. These APIs WILL change and should not be used in production unless you lock both your Vue and Vue Query versions to patch-level versions that are compatible with each other. + +Vue Query can also be used with Vue's new [Suspense](https://vuejs.org/guide/built-ins/suspense.html) API's. + +To do that you need to wrap your suspendable component with `Suspense` component provided by Vue + +```vue + + + +``` + +And change your `setup` function in suspendable component to be `async`. Then you can use async `suspense` function that is provided by `vue-query`. + +```vue + +``` + +## Fetch-on-render vs Render-as-you-fetch + +Out of the box, Vue Query in `suspense` mode works really well as a **Fetch-on-render** solution with no additional configuration. This means that when your components attempt to mount, they will trigger query fetching and suspend, but only once you have imported them and mounted them. If you want to take it to the next level and implement a **Render-as-you-fetch** model, we recommend implementing [Prefetching](../guides/prefetching) on routing callbacks and/or user interactions events to start loading queries before they are mounted and hopefully even before you start importing or mounting their parent components. diff --git a/docs/vue/guides/testing.md b/docs/vue/guides/testing.md new file mode 100644 index 0000000000..38d58cc3c2 --- /dev/null +++ b/docs/vue/guides/testing.md @@ -0,0 +1,4 @@ +--- +id: testing +title: Testing +--- diff --git a/docs/vue/guides/updates-from-mutation-responses.md b/docs/vue/guides/updates-from-mutation-responses.md new file mode 100644 index 0000000000..5f0edb0cd5 --- /dev/null +++ b/docs/vue/guides/updates-from-mutation-responses.md @@ -0,0 +1,5 @@ +--- +id: updates-from-mutation-responses +title: Updates from Mutation Responses +ref: docs/react/guides/updates-from-mutation-responses.md +--- diff --git a/docs/vue/guides/window-focus-refetching.md b/docs/vue/guides/window-focus-refetching.md new file mode 100644 index 0000000000..84c2ea0b9f --- /dev/null +++ b/docs/vue/guides/window-focus-refetching.md @@ -0,0 +1,25 @@ +--- +id: window-focus-refetching +title: Window Focus Refetching +ref: docs/react/guides/window-focus-refetching.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- + +[//]: # 'Example' + +```js +const vueQueryPluginOptions: VueQueryPluginOptions = { + queryClientConfig: { + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + }, + }, + }, +} +app.use(VueQueryPlugin, vueQueryPluginOptions) +``` + +[//]: # 'Example' +[//]: # 'ReactNative' +[//]: # 'ReactNative' From e1e957c56647d98b1abd0ee4476b7d92f6276cfc Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Mon, 26 Dec 2022 18:23:42 +0100 Subject: [PATCH 5/7] docs: vue-query api reference --- docs/config.json | 82 +++++++++++++++++++ docs/react/reference/QueryCache.md | 2 +- docs/react/reference/QueryClient.md | 4 +- docs/react/reference/focusManager.md | 2 +- docs/react/reference/hydration.md | 7 ++ docs/react/reference/onlineManager.md | 2 +- .../lukemorales-query-key-factory.md | 5 ++ docs/vue/community/tkdodos-blog.md | 5 ++ docs/vue/reference/InfiniteQueryObserver.md | 6 ++ docs/vue/reference/MutationCache.md | 6 ++ docs/vue/reference/QueriesObserver.md | 6 ++ docs/vue/reference/QueryCache.md | 6 ++ docs/vue/reference/QueryClient.md | 6 ++ docs/vue/reference/QueryObserver.md | 6 ++ docs/vue/reference/focusManager.md | 6 ++ docs/vue/reference/hydration.md | 11 +++ docs/vue/reference/onlineManager.md | 6 ++ docs/vue/reference/useInfiniteQuery.md | 6 ++ docs/vue/reference/useIsFetching.md | 6 ++ docs/vue/reference/useIsMutating.md | 6 ++ docs/vue/reference/useMutation.md | 6 ++ docs/vue/reference/useQueries.md | 6 ++ docs/vue/reference/useQuery.md | 6 ++ docs/vue/reference/useQueryClient.md | 6 ++ 24 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 docs/vue/community/lukemorales-query-key-factory.md create mode 100644 docs/vue/community/tkdodos-blog.md create mode 100644 docs/vue/reference/InfiniteQueryObserver.md create mode 100644 docs/vue/reference/MutationCache.md create mode 100644 docs/vue/reference/QueriesObserver.md create mode 100644 docs/vue/reference/QueryCache.md create mode 100644 docs/vue/reference/QueryClient.md create mode 100644 docs/vue/reference/QueryObserver.md create mode 100644 docs/vue/reference/focusManager.md create mode 100644 docs/vue/reference/hydration.md create mode 100644 docs/vue/reference/onlineManager.md create mode 100644 docs/vue/reference/useInfiniteQuery.md create mode 100644 docs/vue/reference/useIsFetching.md create mode 100644 docs/vue/reference/useIsMutating.md create mode 100644 docs/vue/reference/useMutation.md create mode 100644 docs/vue/reference/useQueries.md create mode 100644 docs/vue/reference/useQuery.md create mode 100644 docs/vue/reference/useQueryClient.md diff --git a/docs/config.json b/docs/config.json index 3c7b3ee29b..25b857f5df 100644 --- a/docs/config.json +++ b/docs/config.json @@ -575,6 +575,88 @@ "to": "vue/guides/does-this-replace-client-state" } ] + }, + { + "label": "Community Resources", + "children": [ + { + "label": "TkDodo's Blog", + "to": "vue/community/tkdodos-blog" + }, + { + "label": "Query Key Factory", + "to": "vue/community/lukemorales-query-key-factory" + } + ] + }, + { + "label": "API Reference", + "children": [ + { + "label": "useQuery", + "to": "vue/reference/useQuery" + }, + { + "label": "useQueries", + "to": "vue/reference/useQueries" + }, + { + "label": "useInfiniteQuery", + "to": "vue/reference/useInfiniteQuery" + }, + { + "label": "useMutation", + "to": "vue/reference/useMutation" + }, + { + "label": "useIsFetching", + "to": "vue/reference/useIsFetching" + }, + { + "label": "useIsMutating", + "to": "vue/reference/useIsMutating" + }, + { + "label": "useQueryClient", + "to": "vue/reference/useQueryClient" + }, + { + "label": "QueryClient", + "to": "vue/reference/QueryClient" + }, + { + "label": "QueryCache", + "to": "vue/reference/QueryCache" + }, + { + "label": "MutationCache", + "to": "vue/reference/MutationCache" + }, + { + "label": "QueryObserver", + "to": "vue/reference/QueryObserver" + }, + { + "label": "InfiniteQueryObserver", + "to": "vue/reference/InfiniteQueryObserver" + }, + { + "label": "QueriesObserver", + "to": "vue/reference/QueriesObserver" + }, + { + "label": "focusManager", + "to": "vue/reference/focusManager" + }, + { + "label": "onlineManager", + "to": "vue/reference/onlineManager" + }, + { + "label": "hydration", + "to": "vue/reference/hydration" + } + ] } ] }, diff --git a/docs/react/reference/QueryCache.md b/docs/react/reference/QueryCache.md index 4374a5f86b..6237681232 100644 --- a/docs/react/reference/QueryCache.md +++ b/docs/react/reference/QueryCache.md @@ -3,7 +3,7 @@ id: QueryCache title: QueryCache --- -The `QueryCache` is the storage mechanism for React Query. It stores all the data, meta information and state of queries it contains. +The `QueryCache` is the storage mechanism for Tanstack Query. It stores all the data, meta information and state of queries it contains. **Normally, you will not interact with the QueryCache directly and instead use the `QueryClient` for a specific cache.** diff --git a/docs/react/reference/QueryClient.md b/docs/react/reference/QueryClient.md index 4960382f46..d60dad9b8c 100644 --- a/docs/react/reference/QueryClient.md +++ b/docs/react/reference/QueryClient.md @@ -437,7 +437,7 @@ if (queryClient.isFetching()) { } ``` -React Query also exports a handy [`useIsFetching`](../reference/useIsFetching) hook that will let you subscribe to this state in your components without creating a manual subscription to the query cache. +Tanstack Query also exports a handy [`useIsFetching`](../reference/useIsFetching) hook that will let you subscribe to this state in your components without creating a manual subscription to the query cache. **Options** @@ -457,7 +457,7 @@ if (queryClient.isMutating()) { } ``` -React Query also exports a handy [`useIsMutating`](../reference/useIsMutating) hook that will let you subscribe to this state in your components without creating a manual subscription to the mutation cache. +Tanstack Query also exports a handy [`useIsMutating`](../reference/useIsMutating) hook that will let you subscribe to this state in your components without creating a manual subscription to the mutation cache. **Options** diff --git a/docs/react/reference/focusManager.md b/docs/react/reference/focusManager.md index ad251bd9ee..4777e77bb2 100644 --- a/docs/react/reference/focusManager.md +++ b/docs/react/reference/focusManager.md @@ -3,7 +3,7 @@ id: FocusManager title: FocusManager --- -The `FocusManager` manages the focus state within React Query. +The `FocusManager` manages the focus state within Tanstack Query. It can be used to change the default event listeners or to manually change the focus state. diff --git a/docs/react/reference/hydration.md b/docs/react/reference/hydration.md index 70705f03a7..7b6b7defe6 100644 --- a/docs/react/reference/hydration.md +++ b/docs/react/reference/hydration.md @@ -91,6 +91,8 @@ hydrate(queryClient, dehydratedState, options) If the queries included in dehydration already exist in the queryCache, `hydrate` does not overwrite them and they will be **silently** discarded. +[//]: # 'useHydrate' + ## `useHydrate` `useHydrate` adds a previously dehydrated state into the `queryClient` that would be returned by `useQueryClient()`. If the client already contains data, the new queries will be intelligently merged based on update timestamp. @@ -113,6 +115,9 @@ useHydrate(dehydratedState, options) - `context?: React.Context` - Use this to use a custom React Query context. Otherwise, `defaultContext` will be used. +[//]: # 'useHydrate' +[//]: # 'Hydrate' + ## `Hydrate` `Hydrate` wraps `useHydrate` into component. Can be useful when you need hydrate in class component or need hydrate on same level where `QueryClientProvider` rendered. @@ -135,3 +140,5 @@ function App() { - The default query options to use for the hydrated queries. - `context?: React.Context` - Use this to use a custom React Query context. Otherwise, `defaultContext` will be used. + +[//]: # 'Hydrate' diff --git a/docs/react/reference/onlineManager.md b/docs/react/reference/onlineManager.md index ad5acaab3b..f077244f4f 100644 --- a/docs/react/reference/onlineManager.md +++ b/docs/react/reference/onlineManager.md @@ -3,7 +3,7 @@ id: OnlineManager title: OnlineManager --- -The `OnlineManager` manages the online state within React Query. +The `OnlineManager` manages the online state within Tanstack Query. It can be used to change the default event listeners or to manually change the online state. diff --git a/docs/vue/community/lukemorales-query-key-factory.md b/docs/vue/community/lukemorales-query-key-factory.md new file mode 100644 index 0000000000..73f4b9ec8d --- /dev/null +++ b/docs/vue/community/lukemorales-query-key-factory.md @@ -0,0 +1,5 @@ +--- +id: lukemorales-query-key-factory +title: Query Key Factory +ref: docs/react/community/lukemorales-query-key-factory.md +--- diff --git a/docs/vue/community/tkdodos-blog.md b/docs/vue/community/tkdodos-blog.md new file mode 100644 index 0000000000..4c316813dc --- /dev/null +++ b/docs/vue/community/tkdodos-blog.md @@ -0,0 +1,5 @@ +--- +id: tkdodos-blog +title: TkDodo's Blog +ref: docs/react/community/tkdodos-blog.md +--- diff --git a/docs/vue/reference/InfiniteQueryObserver.md b/docs/vue/reference/InfiniteQueryObserver.md new file mode 100644 index 0000000000..0baafb52d6 --- /dev/null +++ b/docs/vue/reference/InfiniteQueryObserver.md @@ -0,0 +1,6 @@ +--- +id: InfiniteQueryObserver +title: InfiniteQueryObserver +ref: docs/react/reference/InfiniteQueryObserver.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/MutationCache.md b/docs/vue/reference/MutationCache.md new file mode 100644 index 0000000000..201c86a5c0 --- /dev/null +++ b/docs/vue/reference/MutationCache.md @@ -0,0 +1,6 @@ +--- +id: MutationCache +title: MutationCache +ref: docs/react/reference/MutationCache.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/QueriesObserver.md b/docs/vue/reference/QueriesObserver.md new file mode 100644 index 0000000000..3e77fe0f7f --- /dev/null +++ b/docs/vue/reference/QueriesObserver.md @@ -0,0 +1,6 @@ +--- +id: QueriesObserver +title: QueriesObserver +ref: docs/react/reference/QueriesObserver.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/QueryCache.md b/docs/vue/reference/QueryCache.md new file mode 100644 index 0000000000..33cd93b6d9 --- /dev/null +++ b/docs/vue/reference/QueryCache.md @@ -0,0 +1,6 @@ +--- +id: QueryCache +title: QueryCache +ref: docs/react/reference/QueryCache.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/QueryClient.md b/docs/vue/reference/QueryClient.md new file mode 100644 index 0000000000..c4692b5032 --- /dev/null +++ b/docs/vue/reference/QueryClient.md @@ -0,0 +1,6 @@ +--- +id: QueryClient +title: QueryClient +ref: docs/react/reference/QueryClient.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/QueryObserver.md b/docs/vue/reference/QueryObserver.md new file mode 100644 index 0000000000..bd2af78dc1 --- /dev/null +++ b/docs/vue/reference/QueryObserver.md @@ -0,0 +1,6 @@ +--- +id: QueryObserver +title: QueryObserver +ref: docs/react/reference/QueryObserver.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/focusManager.md b/docs/vue/reference/focusManager.md new file mode 100644 index 0000000000..a8b35653ad --- /dev/null +++ b/docs/vue/reference/focusManager.md @@ -0,0 +1,6 @@ +--- +id: FocusManager +title: FocusManager +ref: docs/react/reference/focusManager.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/hydration.md b/docs/vue/reference/hydration.md new file mode 100644 index 0000000000..423b957b62 --- /dev/null +++ b/docs/vue/reference/hydration.md @@ -0,0 +1,11 @@ +--- +id: hydration +title: hydration +ref: docs/react/reference/hydration.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- + +[//]: # 'useHydrate' +[//]: # 'useHydrate' +[//]: # 'Hydrate' +[//]: # 'Hydrate' \ No newline at end of file diff --git a/docs/vue/reference/onlineManager.md b/docs/vue/reference/onlineManager.md new file mode 100644 index 0000000000..a3876eca16 --- /dev/null +++ b/docs/vue/reference/onlineManager.md @@ -0,0 +1,6 @@ +--- +id: OnlineManager +title: OnlineManager +ref: docs/react/reference/onlineManager.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useInfiniteQuery.md b/docs/vue/reference/useInfiniteQuery.md new file mode 100644 index 0000000000..49b3e2cb23 --- /dev/null +++ b/docs/vue/reference/useInfiniteQuery.md @@ -0,0 +1,6 @@ +--- +id: useInfiniteQuery +title: useInfiniteQuery +ref: docs/react/reference/useInfiniteQuery.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useIsFetching.md b/docs/vue/reference/useIsFetching.md new file mode 100644 index 0000000000..9c03fd4bd6 --- /dev/null +++ b/docs/vue/reference/useIsFetching.md @@ -0,0 +1,6 @@ +--- +id: useIsFetching +title: useIsFetching +ref: docs/react/reference/useIsFetching.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useIsMutating.md b/docs/vue/reference/useIsMutating.md new file mode 100644 index 0000000000..6b284fe9e9 --- /dev/null +++ b/docs/vue/reference/useIsMutating.md @@ -0,0 +1,6 @@ +--- +id: useIsMutating +title: useIsMutating +ref: docs/react/reference/useIsMutating.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useMutation.md b/docs/vue/reference/useMutation.md new file mode 100644 index 0000000000..a7adb3ca45 --- /dev/null +++ b/docs/vue/reference/useMutation.md @@ -0,0 +1,6 @@ +--- +id: useMutation +title: useMutation +ref: docs/react/reference/useMutation.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useQueries.md b/docs/vue/reference/useQueries.md new file mode 100644 index 0000000000..f4d4e31ccc --- /dev/null +++ b/docs/vue/reference/useQueries.md @@ -0,0 +1,6 @@ +--- +id: useQueries +title: useQueries +ref: docs/react/reference/useQueries.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useQuery.md b/docs/vue/reference/useQuery.md new file mode 100644 index 0000000000..5219178f9c --- /dev/null +++ b/docs/vue/reference/useQuery.md @@ -0,0 +1,6 @@ +--- +id: useQuery +title: useQuery +ref: docs/react/reference/useQuery.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- diff --git a/docs/vue/reference/useQueryClient.md b/docs/vue/reference/useQueryClient.md new file mode 100644 index 0000000000..21b25a9479 --- /dev/null +++ b/docs/vue/reference/useQueryClient.md @@ -0,0 +1,6 @@ +--- +id: useQueryClient +title: useQueryClient +ref: docs/react/reference/useQueryClient.md +replace: { '@tanstack/react-query': '@tanstack/vue-query' } +--- From dcd082743e946c9d1214f69f84bb3222a2bb1c46 Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Mon, 26 Dec 2022 18:28:00 +0100 Subject: [PATCH 6/7] docs: vue-query examples --- docs/config.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/config.json b/docs/config.json index 25b857f5df..48282e3527 100644 --- a/docs/config.json +++ b/docs/config.json @@ -589,6 +589,27 @@ } ] }, + { + "label": "Examples", + "children": [ + { + "label": "Basic", + "to": "vue/examples/vue/basic" + }, + { + "label": "Vue 2.6", + "to": "vue/examples/vue/2.6-basic" + }, + { + "label": "Nuxt 3", + "to": "vue/examples/vue/nuxt3" + }, + { + "label": "Persister", + "to": "vue/examples/vue/persister" + } + ] + }, { "label": "API Reference", "children": [ From dc82da0cd4535c51a1fbcaaf269109245fe6097c Mon Sep 17 00:00:00 2001 From: Damian Osipiuk Date: Tue, 27 Dec 2022 21:48:16 +0100 Subject: [PATCH 7/7] docs: fix TanStack casing --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 ++-- docs/react/guides/custom-logger.md | 2 +- docs/react/guides/default-query-function.md | 2 +- docs/react/guides/disabling-queries.md | 2 +- .../guides/does-this-replace-client-state.md | 16 ++++++++-------- docs/react/guides/filters.md | 2 +- docs/react/guides/important-defaults.md | 4 ++-- docs/react/guides/infinite-queries.md | 2 +- docs/react/guides/mutations.md | 4 ++-- docs/react/guides/network-mode.md | 12 ++++++------ docs/react/guides/paginated-queries.md | 4 ++-- docs/react/guides/parallel-queries.md | 4 ++-- docs/react/guides/query-cancellation.md | 8 ++++---- docs/react/guides/query-functions.md | 4 ++-- docs/react/guides/query-invalidation.md | 2 +- docs/react/guides/query-keys.md | 2 +- docs/react/guides/query-retries.md | 4 ++-- docs/react/guides/scroll-restoration.md | 4 ++-- docs/react/guides/window-focus-refetching.md | 4 ++-- docs/react/reference/QueryCache.md | 2 +- docs/react/reference/QueryClient.md | 4 ++-- docs/react/reference/focusManager.md | 2 +- docs/react/reference/onlineManager.md | 2 +- examples/react/basic-graphql-request/index.html | 2 +- examples/react/basic-typescript/index.html | 2 +- examples/react/basic/index.html | 2 +- examples/react/default-query-function/index.html | 2 +- examples/react/offline/index.html | 2 +- examples/react/playground/index.html | 2 +- examples/react/react-router/index.html | 2 +- examples/react/rick-morty/index.html | 2 +- examples/react/simple/index.html | 2 +- examples/react/star-wars/index.html | 2 +- examples/react/suspense/index.html | 2 +- 34 files changed, 59 insertions(+), 59 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 01c34dc93e..817bb0a377 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -98,9 +98,9 @@ body: - type: input id: rq-version attributes: - label: Tanstack Query version + label: TanStack Query version description: | - Please let us know the exact version of Tanstack Query you were using when the issue occurred. Please don't just put in "latest", as this is subject to change. + Please let us know the exact version of TanStack Query you were using when the issue occurred. Please don't just put in "latest", as this is subject to change. placeholder: | e.g. v3.30.1 validations: diff --git a/docs/react/guides/custom-logger.md b/docs/react/guides/custom-logger.md index a4c075520b..6213d3f18f 100644 --- a/docs/react/guides/custom-logger.md +++ b/docs/react/guides/custom-logger.md @@ -3,7 +3,7 @@ id: custom-logger title: Custom Logger --- -If you want to change how information is logged by Tanstack Query, you can set a custom logger when creating a `QueryClient`. +If you want to change how information is logged by TanStack Query, you can set a custom logger when creating a `QueryClient`. ```tsx const queryClient = new QueryClient({ diff --git a/docs/react/guides/default-query-function.md b/docs/react/guides/default-query-function.md index 78ee0eb2b8..d670e4a909 100644 --- a/docs/react/guides/default-query-function.md +++ b/docs/react/guides/default-query-function.md @@ -3,7 +3,7 @@ id: default-query-function title: Default Query Function --- -If you find yourself wishing for whatever reason that you could just share the same query function for your entire app and just use query keys to identify what it should fetch, you can do that by providing a **default query function** to Tanstack Query: +If you find yourself wishing for whatever reason that you could just share the same query function for your entire app and just use query keys to identify what it should fetch, you can do that by providing a **default query function** to TanStack Query: [//]: # 'Example' diff --git a/docs/react/guides/disabling-queries.md b/docs/react/guides/disabling-queries.md index 2ec1e04755..d848bd379d 100644 --- a/docs/react/guides/disabling-queries.md +++ b/docs/react/guides/disabling-queries.md @@ -53,7 +53,7 @@ function Todos() { [//]: # 'Example' -Permanently disabling a query opts out of many great features that Tanstack Query has to offer (like background refetches), and it's also not the idiomatic way. It takes you from the declarative approach (defining dependencies when your query should run) into an imperative mode (fetch whenever I click here). It is also not possible to pass parameters to `refetch`. Oftentimes, all you want is a lazy query that defers the initial fetch: +Permanently disabling a query opts out of many great features that TanStack Query has to offer (like background refetches), and it's also not the idiomatic way. It takes you from the declarative approach (defining dependencies when your query should run) into an imperative mode (fetch whenever I click here). It is also not possible to pass parameters to `refetch`. Oftentimes, all you want is a lazy query that defers the initial fetch: ## Lazy Queries diff --git a/docs/react/guides/does-this-replace-client-state.md b/docs/react/guides/does-this-replace-client-state.md index 3d7ead4efd..f695f84127 100644 --- a/docs/react/guides/does-this-replace-client-state.md +++ b/docs/react/guides/does-this-replace-client-state.md @@ -1,18 +1,18 @@ --- id: does-this-replace-client-state -title: Does Tanstack Query replace Redux, MobX or other global state managers? +title: Does TanStack Query replace Redux, MobX or other global state managers? --- Well, let's start with a few important items: -- Tanstack Query is a **server-state** library, responsible for managing asynchronous operations between your server and client -- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like Tanstack Query_ +- TanStack Query is a **server-state** library, responsible for managing asynchronous operations between your server and client +- Redux, MobX, Zustand, etc. are **client-state** libraries that _can be used to store asynchronous data, albeit inefficiently when compared to a tool like TanStack Query_ -With those points in mind, the short answer is that Tanstack Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** +With those points in mind, the short answer is that TanStack Query **replaces the boilerplate code and related wiring used to manage cache data in your client-state and replaces it with just a few lines of code.** -For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to Tanstack Query is usually very tiny. +For a vast majority of applications, the truly **globally accessible client state** that is left over after migrating all of your async code to TanStack Query is usually very tiny. -> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **Tanstack Query is not a replacement for local/client state management**. However, you can use Tanstack Query along side most client state managers with zero issues. +> There are still some circumstances where an application might indeed have a massive amount of synchronous client-only state (like a visual designer or music production application), in which case, you will probably still want a client state manager. In this situation it's important to note that **TanStack Query is not a replacement for local/client state management**. However, you can use TanStack Query along side most client state managers with zero issues. ## A Contrived Example @@ -29,7 +29,7 @@ const globalState = { } ``` -Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to Tanstack Query, our remaining global state would look more like this: +Currently, the global state manager is caching 4 types of server-state: `projects`, `teams`, `tasks`, and `users`. If we were to move these server-state assets to TanStack Query, our remaining global state would look more like this: ```tsx const globalState = { @@ -51,6 +51,6 @@ With all of those things removed, you may ask yourself, **"Is it worth it to kee **And that's up to you!** -But Tanstack Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. +But TanStack Query's role is clear. It removes asynchronous wiring and boilerplate from your application and replaces it with just a few lines of code. What are you waiting for, give it a go already! diff --git a/docs/react/guides/filters.md b/docs/react/guides/filters.md index 44c8e0997f..1b094442ad 100644 --- a/docs/react/guides/filters.md +++ b/docs/react/guides/filters.md @@ -3,7 +3,7 @@ id: filters title: Filters --- -Some methods within Tanstack Query accept a `QueryFilters` or `MutationFilters` object. +Some methods within TanStack Query accept a `QueryFilters` or `MutationFilters` object. ## `Query Filters` diff --git a/docs/react/guides/important-defaults.md b/docs/react/guides/important-defaults.md index 1721cb4563..6d12ba6f5b 100644 --- a/docs/react/guides/important-defaults.md +++ b/docs/react/guides/important-defaults.md @@ -3,7 +3,7 @@ id: important-defaults title: Important Defaults --- -Out of the box, Tanstack Query is configured with **aggressive but sane** defaults. **Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.** Keep them in mind as you continue to learn and use Tanstack Query: +Out of the box, TanStack Query is configured with **aggressive but sane** defaults. **Sometimes these defaults can catch new users off guard or make learning/debugging difficult if they are unknown by the user.** Keep them in mind as you continue to learn and use TanStack Query: - Query instances via `useQuery` or `useInfiniteQuery` by default **consider cached data as stale**. @@ -15,7 +15,7 @@ Out of the box, Tanstack Query is configured with **aggressive but sane** defaul - The network is reconnected - The query is optionally configured with a refetch interval -If you see a refetch that you are not expecting, it is likely because you just focused the window and Tanstack Query is doing a [`refetchOnWindowFocus`](../guides/window-focus-refetching). During development, this will probably be triggered more frequently, especially because focusing between the Browser DevTools and your app will also cause a fetch, so be aware of that. +If you see a refetch that you are not expecting, it is likely because you just focused the window and TanStack Query is doing a [`refetchOnWindowFocus`](../guides/window-focus-refetching). During development, this will probably be triggered more frequently, especially because focusing between the Browser DevTools and your app will also cause a fetch, so be aware of that. > To change this functionality, you can use options like `refetchOnMount`, `refetchOnWindowFocus`, `refetchOnReconnect` and `refetchInterval`. diff --git a/docs/react/guides/infinite-queries.md b/docs/react/guides/infinite-queries.md index 8c55e9041f..8f0a032f82 100644 --- a/docs/react/guides/infinite-queries.md +++ b/docs/react/guides/infinite-queries.md @@ -3,7 +3,7 @@ id: infinite-queries title: Infinite Queries --- -Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. Tanstack Query supports a useful version of `useQuery` called `useInfiniteQuery` for querying these types of lists. +Rendering lists that can additively "load more" data onto an existing set of data or "infinite scroll" is also a very common UI pattern. TanStack Query supports a useful version of `useQuery` called `useInfiniteQuery` for querying these types of lists. When using `useInfiniteQuery`, you'll notice a few things are different: diff --git a/docs/react/guides/mutations.md b/docs/react/guides/mutations.md index 43f8c4bd5d..790396deb5 100644 --- a/docs/react/guides/mutations.md +++ b/docs/react/guides/mutations.md @@ -3,7 +3,7 @@ id: mutations title: Mutations --- -Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects. For this purpose, Tanstack Query exports a `useMutation` hook. +Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects. For this purpose, TanStack Query exports a `useMutation` hook. Here's an example of a mutation that adds a new todo to the server: @@ -266,7 +266,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' diff --git a/docs/react/guides/network-mode.md b/docs/react/guides/network-mode.md index 6cef69383d..9180b5b6f0 100644 --- a/docs/react/guides/network-mode.md +++ b/docs/react/guides/network-mode.md @@ -3,9 +3,9 @@ id: network-mode title: Network Mode --- -Tanstack Query provides three different network modes to distinguish how [Queries](../guides/queries) and [Mutations](../guides/mutations) should behave if you have no network connection. This mode can be set for each Query / Mutation individually, or globally via the query / mutation defaults. +TanStack Query provides three different network modes to distinguish how [Queries](../guides/queries) and [Mutations](../guides/mutations) should behave if you have no network connection. This mode can be set for each Query / Mutation individually, or globally via the query / mutation defaults. -Since Tanstack Query is most often used for data fetching in combination with data fetching libraries, the default network mode is [online](#network-mode-online). +Since TanStack Query is most often used for data fetching in combination with data fetching libraries, the default network mode is [online](#network-mode-online). ## Network Mode: online @@ -19,11 +19,11 @@ The flags `isFetching` and `isPaused` are derived from this state and exposed fo > Keep in mind that it might not be enough to check for `loading` state to show a loading spinner. Queries can be in `state: 'loading'`, but `fetchStatus: 'paused'` if they are mounting for the first time, and you have no network connection. -If a query runs because you are online, but you go offline while the fetch is still happening, Tanstack Query will also pause the retry mechanism. Paused queries will then continue to run once you re-gain network connection. This is independent of `refetchOnReconnect` (which also defaults to `true` in this mode), because it is not a `refetch`, but rather a `continue`. If the query has been [cancelled](../guides/query-cancellation) in the meantime, it will not continue. +If a query runs because you are online, but you go offline while the fetch is still happening, TanStack Query will also pause the retry mechanism. Paused queries will then continue to run once you re-gain network connection. This is independent of `refetchOnReconnect` (which also defaults to `true` in this mode), because it is not a `refetch`, but rather a `continue`. If the query has been [cancelled](../guides/query-cancellation) in the meantime, it will not continue. ## Network Mode: always -In this mode, Tanstack Query will always fetch and ignore the online / offline state. This is likely the mode you want to choose if you use Tanstack Query in an environment where you don't need an active network connection for your Queries to work - e.g. if you just read from `AsyncStorage`, or if you just want to return `Promise.resolve(5)` from your `queryFn`. +In this mode, TanStack Query will always fetch and ignore the online / offline state. This is likely the mode you want to choose if you use TanStack Query in an environment where you don't need an active network connection for your Queries to work - e.g. if you just read from `AsyncStorage`, or if you just want to return `Promise.resolve(5)` from your `queryFn`. - Queries will never be `paused` because you have no network connection. - Retries will also not pause - your Query will go to `error` state if it fails. @@ -31,13 +31,13 @@ In this mode, Tanstack Query will always fetch and ignore the online / offline s ## Network Mode: offlineFirst -This mode is the middle ground between the first two options, where Tanstack Query will run the `queryFn` once, but then pause retries. This is very handy if you have a serviceWorker that intercepts a request for caching like in an [offline-first PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers), or if you use HTTP caching via the [Cache-Control header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#the_cache-control_header). +This mode is the middle ground between the first two options, where TanStack Query will run the `queryFn` once, but then pause retries. This is very handy if you have a serviceWorker that intercepts a request for caching like in an [offline-first PWA](https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Offline_Service_workers), or if you use HTTP caching via the [Cache-Control header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching#the_cache-control_header). In those situations, the first fetch might succeed because it comes from an offline storage / cache. However, if there is a cache miss, the network request will go out and fail, in which case this mode behaves like an `online` query - pausing retries. ## Devtools -The [Tanstack Query Devtools](../devtools) will show Queries in a `paused` state if they would be fetching, but there is no network connection. There is also a toggle button to _Mock offline behavior_. Please note that this button will _not_ actually mess with your network connection (you can do that in the browser devtools), but it will set the [OnlineManager](../reference/onlineManager) in an offline state. +The [TanStack Query Devtools](../devtools) will show Queries in a `paused` state if they would be fetching, but there is no network connection. There is also a toggle button to _Mock offline behavior_. Please note that this button will _not_ actually mess with your network connection (you can do that in the browser devtools), but it will set the [OnlineManager](../reference/onlineManager) in an offline state. ## Signature diff --git a/docs/react/guides/paginated-queries.md b/docs/react/guides/paginated-queries.md index 45066af302..b1bbe85f4d 100644 --- a/docs/react/guides/paginated-queries.md +++ b/docs/react/guides/paginated-queries.md @@ -3,7 +3,7 @@ id: paginated-queries title: Paginated / Lagged Queries --- -Rendering paginated data is a very common UI pattern and in Tanstack Query, it "just works" by including the page information in the query key: +Rendering paginated data is a very common UI pattern and in TanStack Query, it "just works" by including the page information in the query key: [//]: # 'Example' ```tsx @@ -18,7 +18,7 @@ However, if you run this simple example, you might notice something strange: **The UI jumps in and out of the `success` and `loading` states because each new page is treated like a brand new query.** -This experience is not optimal and unfortunately is how many tools today insist on working. But not Tanstack Query! As you may have guessed, Tanstack Query comes with an awesome feature called `keepPreviousData` that allows us to get around this. +This experience is not optimal and unfortunately is how many tools today insist on working. But not TanStack Query! As you may have guessed, TanStack Query comes with an awesome feature called `keepPreviousData` that allows us to get around this. ## Better Paginated Queries with `keepPreviousData` diff --git a/docs/react/guides/parallel-queries.md b/docs/react/guides/parallel-queries.md index a54344c921..02c4abed87 100644 --- a/docs/react/guides/parallel-queries.md +++ b/docs/react/guides/parallel-queries.md @@ -7,7 +7,7 @@ title: Parallel Queries ## Manual Parallel Queries -When the number of parallel queries does not change, there is **no extra effort** to use parallel queries. Just use any number of Tanstack Query's `useQuery` and `useInfiniteQuery` hooks side-by-side! +When the number of parallel queries does not change, there is **no extra effort** to use parallel queries. Just use any number of TanStack Query's `useQuery` and `useInfiniteQuery` hooks side-by-side! [//]: # 'Example' @@ -30,7 +30,7 @@ function App () { ## Dynamic Parallel Queries with `useQueries` -If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, Tanstack Query provides a `useQueries` hook, which you can use to dynamically execute as many queries in parallel as you'd like. +If the number of queries you need to execute is changing from render to render, you cannot use manual querying since that would violate the rules of hooks. Instead, TanStack Query provides a `useQueries` hook, which you can use to dynamically execute as many queries in parallel as you'd like. `useQueries` accepts an **options object** with a **queries key** whose value is an **array of query objects**. It returns an **array of query results**: diff --git a/docs/react/guides/query-cancellation.md b/docs/react/guides/query-cancellation.md index 87504d2eed..e7cefdfb7c 100644 --- a/docs/react/guides/query-cancellation.md +++ b/docs/react/guides/query-cancellation.md @@ -3,7 +3,7 @@ id: query-cancellation title: Query Cancellation --- -Tanstack Query provides each query function with an [`AbortSignal` instance](https://developer.mozilla.org/docs/Web/API/AbortSignal), **if it's available in your runtime environment**. When a query becomes out-of-date or inactive, this `signal` will become aborted. This means that all queries are cancellable, and you can respond to the cancellation inside your query function if desired. The best part about this is that it allows you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation. +TanStack Query provides each query function with an [`AbortSignal` instance](https://developer.mozilla.org/docs/Web/API/AbortSignal), **if it's available in your runtime environment**. When a query becomes out-of-date or inactive, this `signal` will become aborted. This means that all queries are cancellable, and you can respond to the cancellation inside your query function if desired. The best part about this is that it allows you to continue to use normal async/await syntax while getting all the benefits of automatic cancellation. The `AbortController` API is available in [most runtime environments](https://developer.mozilla.org/docs/Web/API/AbortController#browser_compatibility), but if the runtime environment does not support it then the query function will receive `undefined` in its place. You may choose to polyfill the `AbortController` API if you wish, there are [several available](https://www.npmjs.com/search?q=abortcontroller%20polyfill). @@ -80,9 +80,9 @@ const query = useQuery({ cancelToken: source.token, }) - // Cancel the request if Tanstack Query signals to abort + // Cancel the request if TanStack Query signals to abort signal?.addEventListener('abort', () => { - source.cancel('Query was cancelled by Tanstack Query') + source.cancel('Query was cancelled by TanStack Query') }) return promise @@ -159,7 +159,7 @@ const query = useQuery({ ## Manual Cancellation -You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call `queryClient.cancelQueries({ queryKey })`, which will cancel the query and revert it back to its previous state. If you have consumed the `signal` passed to the query function, Tanstack Query will additionally also cancel the Promise. +You might want to cancel a query manually. For example, if the request takes a long time to finish, you can allow the user to click a cancel button to stop the request. To do this, you just need to call `queryClient.cancelQueries({ queryKey })`, which will cancel the query and revert it back to its previous state. If you have consumed the `signal` passed to the query function, TanStack Query will additionally also cancel the Promise. [//]: # 'Example7' diff --git a/docs/react/guides/query-functions.md b/docs/react/guides/query-functions.md index 04e52a5c7e..73d9862dfb 100644 --- a/docs/react/guides/query-functions.md +++ b/docs/react/guides/query-functions.md @@ -29,7 +29,7 @@ useQuery({ ## Handling and Throwing Errors -For Tanstack Query to determine a query has errored, the query function **must throw** or return a **rejected Promise**. Any error that is thrown in the query function will be persisted on the `error` state of the query. +For TanStack Query to determine a query has errored, the query function **must throw** or return a **rejected Promise**. Any error that is thrown in the query function will be persisted on the `error` state of the query. [//]: # 'Example2' @@ -104,7 +104,7 @@ The `QueryFunctionContext` is the object passed to each query function. It consi - only for [Infinite Queries](../guides/infinite-queries) - the page parameter used to fetch the current page - `signal?: AbortSignal` - - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance provided by Tanstack Query + - [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) instance provided by TanStack Query - Can be used for [Query Cancellation](../guides/query-cancellation) - `meta: Record | undefined` - an optional field you can fill with additional information about your query diff --git a/docs/react/guides/query-invalidation.md b/docs/react/guides/query-invalidation.md index 73b1c026cf..6fb7b79022 100644 --- a/docs/react/guides/query-invalidation.md +++ b/docs/react/guides/query-invalidation.md @@ -16,7 +16,7 @@ queryClient.invalidateQueries({ queryKey: ['todos'] }) [//]: # 'Example' -> Note: Where other libraries that use normalized caches would attempt to update local queries with the new data either imperatively or via schema inference, Tanstack Query gives you the tools to avoid the manual labor that comes with maintaining normalized caches and instead prescribes **targeted invalidation, background-refetching and ultimately atomic updates**. +> Note: Where other libraries that use normalized caches would attempt to update local queries with the new data either imperatively or via schema inference, TanStack Query gives you the tools to avoid the manual labor that comes with maintaining normalized caches and instead prescribes **targeted invalidation, background-refetching and ultimately atomic updates**. When a query is invalidated with `invalidateQueries`, two things happen: diff --git a/docs/react/guides/query-keys.md b/docs/react/guides/query-keys.md index 4c75ce3abc..78e52d076e 100644 --- a/docs/react/guides/query-keys.md +++ b/docs/react/guides/query-keys.md @@ -3,7 +3,7 @@ id: query-keys title: Query Keys --- -At its core, Tanstack Query manages query caching for you based on query keys. Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. As long as the query key is serializable, and **unique to the query's data**, you can use it! +At its core, TanStack Query manages query caching for you based on query keys. Query keys have to be an Array at the top level, and can be as simple as an Array with a single string, or as complex as an array of many strings and nested objects. As long as the query key is serializable, and **unique to the query's data**, you can use it! ## Simple Query Keys diff --git a/docs/react/guides/query-retries.md b/docs/react/guides/query-retries.md index 87876579b8..e955eeb628 100644 --- a/docs/react/guides/query-retries.md +++ b/docs/react/guides/query-retries.md @@ -3,7 +3,7 @@ id: query-retries title: Query Retries --- -When a `useQuery` query fails (the query function throws an error), Tanstack Query will automatically retry the query if that query's request has not reached the max number of consecutive retries (defaults to `3`) or a function is provided to determine if a retry is allowed. +When a `useQuery` query fails (the query function throws an error), TanStack Query will automatically retry the query if that query's request has not reached the max number of consecutive retries (defaults to `3`) or a function is provided to determine if a retry is allowed. You can configure retries both on a global level and an individual query level. @@ -29,7 +29,7 @@ const result = useQuery({ ## Retry Delay -By default, retries in Tanstack Query do not happen immediately after a request fails. As is standard, a back-off delay is gradually applied to each retry attempt. +By default, retries in TanStack Query do not happen immediately after a request fails. As is standard, a back-off delay is gradually applied to each retry attempt. The default `retryDelay` is set to double (starting at `1000`ms) with each attempt, but not exceed 30 seconds: diff --git a/docs/react/guides/scroll-restoration.md b/docs/react/guides/scroll-restoration.md index 288688d233..6b8d0267bd 100644 --- a/docs/react/guides/scroll-restoration.md +++ b/docs/react/guides/scroll-restoration.md @@ -3,6 +3,6 @@ id: scroll-restoration title: Scroll Restoration --- -Traditionally, when you navigate to a previously visited page on a web browser, you would find that the page would be scrolled to the exact position where you were before you navigated away from that page. This is called **scroll restoration** and has been in a bit of a regression since web applications have started moving towards client side data fetching. With Tanstack Query however, that's no longer the case. +Traditionally, when you navigate to a previously visited page on a web browser, you would find that the page would be scrolled to the exact position where you were before you navigated away from that page. This is called **scroll restoration** and has been in a bit of a regression since web applications have started moving towards client side data fetching. With TanStack Query however, that's no longer the case. -Out of the box, "scroll restoration" for all queries (including paginated and infinite queries) Just Works™️ in Tanstack Query. The reason for this is that query results are cached and able to be retrieved synchronously when a query is rendered. As long as your queries are being cached long enough (the default time is 5 minutes) and have not been garbage collected, scroll restoration will work out of the box all the time. +Out of the box, "scroll restoration" for all queries (including paginated and infinite queries) Just Works™️ in TanStack Query. The reason for this is that query results are cached and able to be retrieved synchronously when a query is rendered. As long as your queries are being cached long enough (the default time is 5 minutes) and have not been garbage collected, scroll restoration will work out of the box all the time. diff --git a/docs/react/guides/window-focus-refetching.md b/docs/react/guides/window-focus-refetching.md index 0e6da62941..fb59ce999b 100644 --- a/docs/react/guides/window-focus-refetching.md +++ b/docs/react/guides/window-focus-refetching.md @@ -3,7 +3,7 @@ id: window-focus-refetching title: Window Focus Refetching --- -If a user leaves your application and returns to stale data, **Tanstack Query automatically requests fresh data for you in the background**. You can disable this globally or per-query using the `refetchOnWindowFocus` option: +If a user leaves your application and returns to stale data, **TanStack Query automatically requests fresh data for you in the background**. You can disable this globally or per-query using the `refetchOnWindowFocus` option: #### Disabling Globally @@ -42,7 +42,7 @@ useQuery({ ## Custom Window Focus Event -In rare circumstances, you may want to manage your own window focus events that trigger Tanstack Query to revalidate. To do this, Tanstack Query provides a `focusManager.setEventListener` function that supplies you the callback that should be fired when the window is focused and allows you to set up your own events. When calling `focusManager.setEventListener`, the previously set handler is removed (which in most cases will be the default handler) and your new handler is used instead. For example, this is the default handler: +In rare circumstances, you may want to manage your own window focus events that trigger TanStack Query to revalidate. To do this, TanStack Query provides a `focusManager.setEventListener` function that supplies you the callback that should be fired when the window is focused and allows you to set up your own events. When calling `focusManager.setEventListener`, the previously set handler is removed (which in most cases will be the default handler) and your new handler is used instead. For example, this is the default handler: [//]: # 'Example3' diff --git a/docs/react/reference/QueryCache.md b/docs/react/reference/QueryCache.md index 6237681232..f3f0e7dd39 100644 --- a/docs/react/reference/QueryCache.md +++ b/docs/react/reference/QueryCache.md @@ -3,7 +3,7 @@ id: QueryCache title: QueryCache --- -The `QueryCache` is the storage mechanism for Tanstack Query. It stores all the data, meta information and state of queries it contains. +The `QueryCache` is the storage mechanism for TanStack Query. It stores all the data, meta information and state of queries it contains. **Normally, you will not interact with the QueryCache directly and instead use the `QueryClient` for a specific cache.** diff --git a/docs/react/reference/QueryClient.md b/docs/react/reference/QueryClient.md index d60dad9b8c..fb7a6c8ec4 100644 --- a/docs/react/reference/QueryClient.md +++ b/docs/react/reference/QueryClient.md @@ -437,7 +437,7 @@ if (queryClient.isFetching()) { } ``` -Tanstack Query also exports a handy [`useIsFetching`](../reference/useIsFetching) hook that will let you subscribe to this state in your components without creating a manual subscription to the query cache. +TanStack Query also exports a handy [`useIsFetching`](../reference/useIsFetching) hook that will let you subscribe to this state in your components without creating a manual subscription to the query cache. **Options** @@ -457,7 +457,7 @@ if (queryClient.isMutating()) { } ``` -Tanstack Query also exports a handy [`useIsMutating`](../reference/useIsMutating) hook that will let you subscribe to this state in your components without creating a manual subscription to the mutation cache. +TanStack Query also exports a handy [`useIsMutating`](../reference/useIsMutating) hook that will let you subscribe to this state in your components without creating a manual subscription to the mutation cache. **Options** diff --git a/docs/react/reference/focusManager.md b/docs/react/reference/focusManager.md index 4777e77bb2..de9482abd2 100644 --- a/docs/react/reference/focusManager.md +++ b/docs/react/reference/focusManager.md @@ -3,7 +3,7 @@ id: FocusManager title: FocusManager --- -The `FocusManager` manages the focus state within Tanstack Query. +The `FocusManager` manages the focus state within TanStack Query. It can be used to change the default event listeners or to manually change the focus state. diff --git a/docs/react/reference/onlineManager.md b/docs/react/reference/onlineManager.md index f077244f4f..4b6536e9e0 100644 --- a/docs/react/reference/onlineManager.md +++ b/docs/react/reference/onlineManager.md @@ -3,7 +3,7 @@ id: OnlineManager title: OnlineManager --- -The `OnlineManager` manages the online state within Tanstack Query. +The `OnlineManager` manages the online state within TanStack Query. It can be used to change the default event listeners or to manually change the online state. diff --git a/examples/react/basic-graphql-request/index.html b/examples/react/basic-graphql-request/index.html index 27bdf766ca..984f90ddcb 100644 --- a/examples/react/basic-graphql-request/index.html +++ b/examples/react/basic-graphql-request/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Basic GraphQl Request Example App + TanStack Query React Basic GraphQl Request Example App diff --git a/examples/react/basic-typescript/index.html b/examples/react/basic-typescript/index.html index 6d9f50bd62..f20222fbd3 100644 --- a/examples/react/basic-typescript/index.html +++ b/examples/react/basic-typescript/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Basic TypeScript Example App + TanStack Query React Basic TypeScript Example App diff --git a/examples/react/basic/index.html b/examples/react/basic/index.html index fb8b862df9..f75be5068f 100644 --- a/examples/react/basic/index.html +++ b/examples/react/basic/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Basic Example App + TanStack Query React Basic Example App diff --git a/examples/react/default-query-function/index.html b/examples/react/default-query-function/index.html index 21911ae946..61693932eb 100644 --- a/examples/react/default-query-function/index.html +++ b/examples/react/default-query-function/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Default Query Function Example App + TanStack Query React Default Query Function Example App diff --git a/examples/react/offline/index.html b/examples/react/offline/index.html index 9a0f82f68b..69e3e23d0f 100644 --- a/examples/react/offline/index.html +++ b/examples/react/offline/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Offline Example App + TanStack Query React Offline Example App diff --git a/examples/react/playground/index.html b/examples/react/playground/index.html index 18fec2fda7..99cca4c3fa 100644 --- a/examples/react/playground/index.html +++ b/examples/react/playground/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Playgorund Example App + TanStack Query React Playgorund Example App diff --git a/examples/react/react-router/index.html b/examples/react/react-router/index.html index e4634dceaf..4e93947879 100644 --- a/examples/react/react-router/index.html +++ b/examples/react/react-router/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Router Example App + TanStack Query React Router Example App diff --git a/examples/react/rick-morty/index.html b/examples/react/rick-morty/index.html index 747e5b4c5a..4ab314f7dd 100644 --- a/examples/react/rick-morty/index.html +++ b/examples/react/rick-morty/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Rick And Morty Example App + TanStack Query React Rick And Morty Example App diff --git a/examples/react/simple/index.html b/examples/react/simple/index.html index 31f2cb2baf..bede960426 100644 --- a/examples/react/simple/index.html +++ b/examples/react/simple/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Simple Example App + TanStack Query React Simple Example App diff --git a/examples/react/star-wars/index.html b/examples/react/star-wars/index.html index acd8b85651..3f9d49f06e 100644 --- a/examples/react/star-wars/index.html +++ b/examples/react/star-wars/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Star Wars Example App + TanStack Query React Star Wars Example App diff --git a/examples/react/suspense/index.html b/examples/react/suspense/index.html index e7dd9fdce2..57df3f9dd5 100644 --- a/examples/react/suspense/index.html +++ b/examples/react/suspense/index.html @@ -6,7 +6,7 @@ - Tanstack Query React Suspense Example App + TanStack Query React Suspense Example App