@@ -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/custom-logger.md b/docs/react/guides/custom-logger.md
index 8cc9dd330e..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 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 e9baf3d9f6..d670e4a909 100644
--- a/docs/react/guides/default-query-function.md
+++ b/docs/react/guides/default-query-function.md
@@ -3,14 +3,18 @@ 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'
```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/guides/disabling-queries.md b/docs/react/guides/disabling-queries.md
index 529c869374..d848bd379d 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 (
@@ -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..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 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..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 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..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, 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..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. 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: `` as this would send the onClick event to the `fetchNextPage` function.
+[//]: # 'Example'
+
```tsx
import { useInfiniteQuery } from '@tanstack/react-query'
function Projects() {
const fetchProjects = async ({ pageParam = 0 }) => {
- const res = await fetch('/api/projects?cursor=' + pageParam);
- return res.json();
+ const res = await fetch('/api/projects?cursor=' + pageParam)
+ return res.json()
}
const {
@@ -72,7 +74,7 @@ function Projects() {
<>
{data.pages.map((group, i) => (
- {group.projects.map(project => (
+ {group.projects.map((project) => (
{project.name}
))}
@@ -95,6 +97,8 @@ function Projects() {
}
```
+[//]: # 'Example'
+
## What happens when an infinite query needs to be refetched?
When an infinite query becomes `stale` and needs to be refetched, each group is fetched `sequentially`, starting from the first one. This ensures that even if the underlying data is mutated, we're not using stale cursors and potentially getting duplicates or skipping records. If an infinite query's results are ever removed from the queryCache, the pagination restarts at the initial state with only the initial group being requested.
@@ -103,6 +107,8 @@ When an infinite query becomes `stale` and needs to be refetched, each group is
If you only want to actively refetch a subset of all pages, you can pass the `refetchPage` function to `refetch` returned from `useInfiniteQuery`.
+[//]: # 'Example2'
+
```tsx
const { refetch } = useInfiniteQuery({
queryKey: ['projects'],
@@ -114,6 +120,8 @@ const { refetch } = useInfiniteQuery({
refetch({ refetchPage: (page, index) => index === 0 })
```
+[//]: # 'Example2'
+
You can also pass this function as part of the 2nd argument (`queryFilters`) to [queryClient.refetchQueries](../reference/QueryClient#queryclientrefetchqueries), [queryClient.invalidateQueries](../reference/QueryClient#queryclientinvalidatequeries) or [queryClient.resetQueries](../reference/QueryClient#queryclientresetqueries).
**Signature**
@@ -126,6 +134,8 @@ The function is executed for each page, and only pages where this function retur
By default, the variable returned from `getNextPageParam` will be supplied to the query function, but in some cases, you may want to override this. You can pass custom variables to the `fetchNextPage` function which will override the default variable like so:
+[//]: # 'Example3'
+
```tsx
function Projects() {
const fetchProjects = ({ pageParam = 0 }) =>
@@ -149,10 +159,14 @@ function Projects() {
}
```
+[//]: # 'Example3'
+
## What if I want to implement a bi-directional infinite list?
Bi-directional lists can be implemented by using the `getPreviousPageParam`, `fetchPreviousPage`, `hasPreviousPage` and `isFetchingPreviousPage` properties and functions.
+[//]: # 'Example4'
+
```tsx
useInfiniteQuery({
queryKey: ['projects'],
@@ -162,43 +176,58 @@ useInfiniteQuery({
})
```
+[//]: # 'Example4'
+
## What if I want to show the pages in reversed order?
Sometimes you may want to show the pages in reversed order. If this is case, you can use the `select` option:
+[//]: # 'Example5'
+
```tsx
useInfiniteQuery({
queryKey: ['projects'],
queryFn: fetchProjects,
- select: data => ({
+ select: (data) => ({
pages: [...data.pages].reverse(),
pageParams: [...data.pageParams].reverse(),
}),
})
```
+[//]: # 'Example5'
+
## What if I want to manually update the infinite query?
Manually removing first page:
+[//]: # 'Example6'
+
```tsx
-queryClient.setQueryData(['projects'], data => ({
+queryClient.setQueryData(['projects'], (data) => ({
pages: data.pages.slice(1),
pageParams: data.pageParams.slice(1),
}))
```
+[//]: # 'Example6'
+
Manually removing a single value from an individual page:
+[//]: # 'Example7'
+
```tsx
-const newPagesArray = oldPagesArray?.pages.map((page) =>
- page.filter((val) => val.id !== updatedId)
-) ?? []
+const newPagesArray =
+ oldPagesArray?.pages.map((page) =>
+ page.filter((val) => val.id !== updatedId),
+ ) ?? []
-queryClient.setQueryData(['projects'], data => ({
+queryClient.setQueryData(['projects'], (data) => ({
pages: newPagesArray,
pageParams: data.pageParams,
}))
```
+[//]: # 'Example7'
+
Make sure to keep the same data structure of pages and pageParams!
diff --git a/docs/react/guides/initial-query-data.md b/docs/react/guides/initial-query-data.md
index 4744cb1256..f231e0e8b9 100644
--- a/docs/react/guides/initial-query-data.md
+++ b/docs/react/guides/initial-query-data.md
@@ -17,136 +17,159 @@ There may be times when you already have the initial data for a query available
> IMPORTANT: `initialData` is persisted to the cache, so it is not recommended to provide placeholder, partial or incomplete data to this option and instead use `placeholderData`
+[//]: # 'Example'
+
```tsx
-function Todos() {
- const result = useQuery({
- queryKey: ['todos'],
- queryFn: () => fetch('/todos'),
- initialData: initialTodos,
- })
-}
+const result = useQuery({
+ queryKey: ['todos'],
+ queryFn: () => fetch('/todos'),
+ initialData: initialTodos,
+})
```
+[//]: # 'Example'
+
### `staleTime` and `initialDataUpdatedAt`
By default, `initialData` is treated as totally fresh, as if it were just fetched. This also means that it will affect how it is interpreted by the `staleTime` option.
- If you configure your query observer with `initialData`, and no `staleTime` (the default `staleTime: 0`), the query will immediately refetch when it mounts:
+ [//]: # 'Example2'
+
```tsx
- function Todos() {
- // Will show initialTodos immediately, but also immediately refetch todos after mount
- const result = useQuery({
- queryKey: ['todos'],
- queryFn: () => fetch('/todos'),
- initialData: initialTodos,
- })
- }
+ // Will show initialTodos immediately, but also immediately refetch todos after mount
+ const result = useQuery({
+ queryKey: ['todos'],
+ queryFn: () => fetch('/todos'),
+ initialData: initialTodos,
+ })
```
+ [//]: # 'Example2'
+
- If you configure your query observer with `initialData` and a `staleTime` of `1000` ms, the data will be considered fresh for that same amount of time, as if it was just fetched from your query function.
+ [//]: # 'Example3'
+
```tsx
- function Todos() {
- // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
- const result = useQuery({
- queryKey: ['todos'],
- queryFn: () => fetch('/todos'),
- initialData: initialTodos,
- staleTime: 1000,
- })
- }
+ // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
+ const result = useQuery({
+ queryKey: ['todos'],
+ queryFn: () => fetch('/todos'),
+ initialData: initialTodos,
+ staleTime: 1000,
+ })
```
+ [//]: # 'Example3'
+
- So what if your `initialData` isn't totally fresh? That leaves us with the last configuration that is actually the most accurate and uses an option called `initialDataUpdatedAt`. This option allows you to pass a numeric JS timestamp in milliseconds of when the initialData itself was last updated, e.g. what `Date.now()` provides. Take note that if you have a unix timestamp, you'll need to convert it to a JS timestamp by multiplying it by `1000`.
-```tsx
- function Todos() {
- // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
- const result = useQuery({
- queryKey: ['todos'],
- queryFn: () => fetch('/todos'),
- initialData: initialTodos,
- staleTime: 60 * 1000, // 1 minute
- // This could be 10 seconds ago or 10 minutes ago
- initialDataUpdatedAt: initialTodosUpdatedTimestamp // eg. 1608412420052
- })
- }
-```
+
+ [//]: # 'Example4'
+
+ ```tsx
+ // Show initialTodos immediately, but won't refetch until another interaction event is encountered after 1000 ms
+ const result = useQuery({
+ queryKey: ['todos'],
+ queryFn: () => fetch('/todos'),
+ initialData: initialTodos,
+ staleTime: 60 * 1000, // 1 minute
+ // This could be 10 seconds ago or 10 minutes ago
+ initialDataUpdatedAt: initialTodosUpdatedTimestamp, // eg. 1608412420052
+ })
+ ```
+
+ [//]: # 'Example4'
+
This option allows the staleTime to be used for its original purpose, determining how fresh the data needs to be, while also allowing the data to be refetched on mount if the `initialData` is older than the `staleTime`. In the example above, our data needs to be fresh within 1 minute, and we can hint to the query when the initialData was last updated so the query can decide for itself whether the data needs to be refetched again or not.
-> If you would rather treat your data as **prefetched data**, we recommend that you use the `prefetchQuery` or `fetchQuery` APIs to populate the cache beforehand, thus letting you configure your `staleTime` independently from your initialData
+ > If you would rather treat your data as **prefetched data**, we recommend that you use the `prefetchQuery` or `fetchQuery` APIs to populate the cache beforehand, thus letting you configure your `staleTime` independently from your initialData
### Initial Data Function
If the process for accessing a query's initial data is intensive or just not something you want to perform on every render, you can pass a function as the `initialData` value. This function will be executed only once when the query is initialized, saving you precious memory and/or CPU:
+[//]: # 'Example5'
+
```tsx
-function Todos() {
- const result = useQuery({
- queryKey: ['todos'],
- queryFn: () => fetch('/todos'),
- initialData: () => getExpensiveTodos(),
- })
-}
+const result = useQuery({
+ queryKey: ['todos'],
+ queryFn: () => fetch('/todos'),
+ initialData: () => getExpensiveTodos(),
+})
```
+[//]: # 'Example5'
+
### Initial Data from Cache
In some circumstances, you may be able to provide the initial data for a query from the cached result of another. A good example of this would be searching the cached data from a todos list query for an individual todo item, then using that as the initial data for your individual todo query:
+[//]: # 'Example6'
+
```tsx
-function Todo({ todoId }) {
- const result = useQuery(['todo', todoId], () => fetch('/todos'), {
- initialData: () => {
- // Use a todo from the 'todos' query as the initial data for this todo query
- return queryClient.getQueryData(['todos'])?.find(d => d.id === todoId)
- },
- })
-}
+const result = useQuery({
+ queryKey: ['todo', todoId],
+ queryFn: () => fetch('/todos'),
+ initialData: () => {
+ // Use a todo from the 'todos' query as the initial data for this todo query
+ return queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId)
+ },
+})
```
+[//]: # 'Example6'
+
### Initial Data from the cache with `initialDataUpdatedAt`
Getting initial data from the cache means the source query you're using to look up the initial data from is likely old, but `initialData`. Instead of using an artificial `staleTime` to keep your query from refetching immediately, it's suggested that you pass the source query's `dataUpdatedAt` to `initialDataUpdatedAt`. This provides the query instance with all the information it needs to determine if and when the query needs to be refetched, regardless of initial data being provided.
+[//]: # 'Example7'
+
```tsx
-function Todo({ todoId }) {
- const result = useQuery({
- queryKey: ['todos', todoId],
- queryFn: () => fetch(`/todos/${todoId}`),
- initialData: () =>
- queryClient.getQueryData(['todos'])?.find(d => d.id === todoId),
- initialDataUpdatedAt: () =>
- queryClient.getQueryState(['todos'])?.dataUpdatedAt,
- })
-}
+const result = useQuery({
+ queryKey: ['todos', todoId],
+ queryFn: () => fetch(`/todos/${todoId}`),
+ initialData: () =>
+ queryClient.getQueryData(['todos'])?.find((d) => d.id === todoId),
+ initialDataUpdatedAt: () =>
+ queryClient.getQueryState(['todos'])?.dataUpdatedAt,
+})
```
+[//]: # 'Example7'
+
### Conditional Initial Data from Cache
If the source query you're using to look up the initial data from is old, you may not want to use the cached data at all and just fetch from the server. To make this decision easier, you can use the `queryClient.getQueryState` method instead to get more information about the source query, including a `state.dataUpdatedAt` timestamp you can use to decide if the query is "fresh" enough for your needs:
+[//]: # 'Example8'
+
```tsx
-function Todo({ todoId }) {
- const result = useQuery({
- queryKey: ['todo', todoId],
- queryFn: () => fetch(`/todos/${todoId}`),
- initialData: () => {
- // Get the query state
- const state = queryClient.getQueryState(['todos'])
-
- // If the query exists and has data that is no older than 10 seconds...
- if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
- // return the individual todo
- return state.data.find(d => d.id === todoId)
- }
-
- // Otherwise, return undefined and let it fetch from a hard loading state!
- },
- })
-}
+const result = useQuery({
+ queryKey: ['todo', todoId],
+ queryFn: () => fetch(`/todos/${todoId}`),
+ initialData: () => {
+ // Get the query state
+ const state = queryClient.getQueryState(['todos'])
+
+ // If the query exists and has data that is no older than 10 seconds...
+ if (state && Date.now() - state.dataUpdatedAt <= 10 * 1000) {
+ // return the individual todo
+ return state.data.find((d) => d.id === todoId)
+ }
+
+ // Otherwise, return undefined and let it fetch from a hard loading state!
+ },
+})
```
+[//]: # 'Example8'
+[//]: # 'Materials'
+
## Further reading
For a comparison between `Initial Data` and `Placeholder 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/invalidations-from-mutations.md b/docs/react/guides/invalidations-from-mutations.md
index e476c503f5..2f3352e2d3 100644
--- a/docs/react/guides/invalidations-from-mutations.md
+++ b/docs/react/guides/invalidations-from-mutations.md
@@ -1,18 +1,24 @@
---
-id: invalidation-from-mutations
-title: Invalidation from Mutations
+id: invalidations-from-mutations
+title: Invalidations from Mutations
---
Invalidating queries is only half the battle. Knowing **when** to invalidate them is the other half. Usually when a mutation in your app succeeds, it's VERY likely that there are related queries in your application that need to be invalidated and possibly refetched to account for the new changes from your mutation.
For example, assume we have a mutation to post a new todo:
+[//]: # 'Example'
+
```tsx
const mutation = useMutation({ mutationFn: postTodo })
```
+[//]: # 'Example'
+
When a successful `postTodo` mutation happens, we likely want all `todos` queries to get invalidated and possibly refetched to show the new todo item. To do this, you can use `useMutation`'s `onSuccess` options and the `client`'s `invalidateQueries` function:
+[//]: # 'Example2'
+
```tsx
import { useMutation, useQueryClient } from '@tanstack/react-query'
@@ -28,4 +34,6 @@ const mutation = useMutation({
})
```
+[//]: # 'Example2'
+
You can wire up your invalidations to happen using any of the callbacks available in the [`useMutation` hook](../guides/mutations)
diff --git a/docs/react/guides/mutations.md b/docs/react/guides/mutations.md
index afc1f6b319..790396deb5 100644
--- a/docs/react/guides/mutations.md
+++ b/docs/react/guides/mutations.md
@@ -3,16 +3,18 @@ id: mutations
title: Mutations
---
-Unlike queries, mutations are typically used to create/update/delete data or perform server side-effects. For this purpose, React 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:
+[//]: # 'Example'
+
```tsx
function App() {
const mutation = useMutation({
- mutationFn: newTodo => {
+ mutationFn: (newTodo) => {
return axios.post('/todos', newTodo)
- }
+ },
})
return (
@@ -41,6 +43,8 @@ function App() {
}
```
+[//]: # 'Example'
+
A mutation can only be in one of the following states at any given moment:
- `isIdle` or `status === 'idle'` - The mutation is currently idle or in a fresh/reset state
@@ -57,25 +61,34 @@ 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'
+[//]: # 'Example2'
+
```tsx
// This will not work in React 16 and earlier
const CreateTodo = () => {
- const mutation = useMutation({ mutationFn: event => {
- event.preventDefault()
- return fetch('/api', new FormData(event.target))
- }})
+ const mutation = useMutation({
+ mutationFn: (event) => {
+ event.preventDefault()
+ return fetch('/api', new FormData(event.target))
+ },
+ })
return
}
// This will work
const CreateTodo = () => {
- const mutation = useMutation({ mutationFn: formData => {
- return fetch('/api', formData)
- }})
- const onSubmit = event => {
+ const mutation = useMutation({
+ mutationFn: (formData) => {
+ return fetch('/api', formData)
+ },
+ })
+ const onSubmit = (event) => {
event.preventDefault()
mutation.mutate(new FormData(event.target))
}
@@ -84,16 +97,20 @@ const CreateTodo = () => {
}
```
+[//]: # 'Example2'
+
## Resetting Mutation State
It's sometimes the case that you need to clear the `error` or `data` of a mutation request. To do this, you can use the `reset` function to handle this:
+[//]: # 'Example3'
+
```tsx
const CreateTodo = () => {
const [title, setTitle] = useState('')
const mutation = useMutation({ mutationFn: createTodo })
- const onCreateTodo = e => {
+ const onCreateTodo = (e) => {
e.preventDefault()
mutation.mutate({ title })
}
@@ -106,7 +123,7 @@ const CreateTodo = () => {
setTitle(e.target.value)}
+ onChange={(e) => setTitle(e.target.value)}
/>
@@ -115,14 +132,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 +162,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 +180,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,11 +213,16 @@ 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,
@@ -197,7 +231,7 @@ useMutation({
},
})
-['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 +239,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 +262,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 +277,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 +301,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 +338,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 +383,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/network-mode.md b/docs/react/guides/network-mode.md
index 96c18892d9..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
---
-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,13 +31,13 @@ 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.
## 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/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..b1bbe85f4d 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..02c4abed87 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/react/guides/query-cancellation.md b/docs/react/guides/query-cancellation.md
index 0cb91fb9c3..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
---
-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..73d9862dfb 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..6fb7b79022 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..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, 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..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), 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..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 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/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/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..fb59ce999b 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/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/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/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/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/reference/QueryCache.md b/docs/react/reference/QueryCache.md
index 4374a5f86b..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 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..fb7a6c8ec4 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..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 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..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 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/react/typescript.md b/docs/react/typescript.md
index 6b67741cd8..004daad70e 100644
--- a/docs/react/typescript.md
+++ b/docs/react/typescript.md
@@ -16,79 +16,104 @@ 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
+ // ^? 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)
-```ts
+[//]: # 'Playground1'
+
+```tsx
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)
+```tsx
+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:
-```ts
+```tsx
const { data, isSuccess } = useQuery({
queryKey: ['test'],
queryFn: () => Promise.resolve(5),
})
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`:
-```ts
+```tsx
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: unknown
if (error instanceof Error) {
error
-// ^? const error: Error
+ // ^? const error: Error
}
```
+[//]: # 'Playground5'
+
[typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAORToCGAxjALQCOO+VAsAFCiSw4dAB7AIqUuUpURY1Nx68YeMOjgBxcsjBwAvIjjAAJgC44AO2QgARriK9eDCOdTwS6GAwAWmiNon6ABQAlGYAClLAGAA8vtoA2gC6AHx6qbLiAHQA5h6BVAD02Vpg8sGZMF7o5oG0qJAuarqpdQ0YmUZ0MHTBDjxOLvBIuORQRHooGNi4eIHxVMV+pVSJADSkHt5xpb08BQVwh0cAegD8fcAkcIEj0IaDdOYM6BBXAKJQo8GIvIe3ULx9nAzrxCEA)
-```ts
+[//]: # 'Playground5'
+
+```tsx
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/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/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..125a176950
--- /dev/null
+++ b/docs/vue/guides/background-fetching-indicators.md
@@ -0,0 +1,45 @@
+---
+id: background-fetching-indicators
+title: Background Fetching Indicators
+ref: docs/react/guides/background-fetching-indicators.md
+---
+
+[//]: # 'Example'
+
+```vue
+
+
+
+
+
+```
+
+[//]: # 'Example4'
+[//]: # 'Materials'
+[//]: # 'Materials'
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
+
+
+
+
{{ data }}
+
+
+
+
+```
+
+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
+
+
+
+
+
{{ data }}
+
+
+
+
+```
+
+## 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
+
+
+
+
+
+
+
+
+
Loading...
+
+
+
+```
+
+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'
diff --git a/docs/vue/installation.md b/docs/vue/installation.md
index 28ab738307..70ec75d080 100644
--- a/docs/vue/installation.md
+++ b/docs/vue/installation.md
@@ -25,10 +25,10 @@ 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);
+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/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' }
+---
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'
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
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);