docs-i18n 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/dist/server/server.js +20 -20
- package/package.json +1 -1
- package/template/app/utils/content-loader.ts +4 -0
- package/template/app/utils/docs.server.ts +7 -0
- package/template/content/blog/en/announcing-query-v5.md +110 -0
- package/template/content/blog/en/hello-world.md +26 -0
- package/template/content/blog/en/i18n-best-practices.md +57 -0
- package/template/content/blog/en/react-query-vs-swr.md +100 -0
- package/template/content/blog/en/state-management-2024.md +143 -0
- package/template/content/blog/en/tanstack-router-1.0.md +121 -0
- package/template/content/blog/ja/announcing-query-v5.md +110 -0
- package/template/content/blog/ja/hello-world.md +26 -0
- package/template/content/blog/zh-hans/announcing-query-v5.md +93 -0
- package/template/content/blog/zh-hans/hello-world.md +26 -0
- package/template/content/docs-i18n/docs.config.json +25 -0
- package/template/content/docs-i18n/en/architecture.md +222 -0
- package/template/content/docs-i18n/en/configuration.md +331 -0
- package/template/content/docs-i18n/en/deployment.md +209 -0
- package/template/content/docs-i18n/en/getting-started.md +168 -0
- package/template/content/docs.config.json +25 -0
- package/template/content/en/admin.md +151 -0
- package/template/content/en/architecture.md +222 -0
- package/template/content/en/cli.md +269 -0
- package/template/content/en/configuration.md +331 -0
- package/template/content/en/deployment.md +209 -0
- package/template/content/en/getting-started.md +168 -0
- package/template/content/form/docs.config.json +18 -0
- package/template/content/form/en/guides/validation.md +175 -0
- package/template/content/form/en/installation.md +63 -0
- package/template/content/form/en/overview.md +71 -0
- package/template/content/form/en/quick-start.md +121 -0
- package/template/content/form/ja/installation.md +63 -0
- package/template/content/form/ja/overview.md +71 -0
- package/template/content/form/zh-hans/installation.md +63 -0
- package/template/content/form/zh-hans/overview.md +71 -0
- package/template/content/query/docs.config.json +32 -0
- package/template/content/query/en/guides/mutations.md +126 -0
- package/template/content/query/en/guides/pagination.md +98 -0
- package/template/content/query/en/guides/queries.md +120 -0
- package/template/content/query/en/installation.md +78 -0
- package/template/content/query/en/overview.md +72 -0
- package/template/content/query/en/quick-start.md +108 -0
- package/template/content/query/ja/installation.md +78 -0
- package/template/content/query/ja/overview.md +72 -0
- package/template/content/query/zh-hans/guides/mutations.md +126 -0
- package/template/content/query/zh-hans/guides/pagination.md +98 -0
- package/template/content/query/zh-hans/guides/queries.md +120 -0
- package/template/content/query/zh-hans/installation.md +95 -0
- package/template/content/query/zh-hans/overview.md +72 -0
- package/template/content/query/zh-hans/quick-start.md +108 -0
- package/template/content/router/docs.config.json +18 -0
- package/template/content/router/en/guides/routing-concepts.md +131 -0
- package/template/content/router/en/installation.md +57 -0
- package/template/content/router/en/overview.md +74 -0
- package/template/content/router/en/quick-start.md +88 -0
- package/template/content/router/ja/installation.md +57 -0
- package/template/content/router/ja/overview.md +78 -0
- package/template/content/router/zh-hans/guides/routing-concepts.md +131 -0
- package/template/content/router/zh-hans/installation.md +57 -0
- package/template/content/router/zh-hans/overview.md +81 -0
- package/template/content/router/zh-hans/quick-start.md +88 -0
- package/template/content/table/docs.config.json +18 -0
- package/template/content/table/en/guides/column-definitions.md +135 -0
- package/template/content/table/en/installation.md +56 -0
- package/template/content/table/en/overview.md +79 -0
- package/template/content/table/en/quick-start.md +112 -0
- package/template/content/table/ja/installation.md +56 -0
- package/template/content/table/ja/overview.md +79 -0
- package/template/content/table/zh-hans/installation.md +56 -0
- package/template/content/table/zh-hans/overview.md +79 -0
- package/template/content/virtual/docs.config.json +18 -0
- package/template/content/virtual/en/guides/dynamic-sizing.md +129 -0
- package/template/content/virtual/en/installation.md +57 -0
- package/template/content/virtual/en/overview.md +74 -0
- package/template/content/virtual/en/quick-start.md +114 -0
- package/template/content/virtual/ja/installation.md +57 -0
- package/template/content/virtual/ja/overview.md +74 -0
- package/template/content/virtual/zh-hans/installation.md +57 -0
- package/template/content/virtual/zh-hans/overview.md +74 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TanStack Form 概览
|
|
3
|
+
description: 无头、高性能、类型安全的表单状态管理
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TanStack Form
|
|
7
|
+
|
|
8
|
+
TanStack Form 是一个无头、高性能、类型安全的表单状态管理库,支持 TS/JS、React、Vue 和 Angular。
|
|
9
|
+
|
|
10
|
+
## 为什么选择 TanStack Form?
|
|
11
|
+
|
|
12
|
+
大多数表单库要么为了便利牺牲了类型安全,要么与特定框架紧密耦合。TanStack Form 两者兼顾——从表单值到验证错误的完整类型安全,并提供 React、Vue 和 Angular 的适配器。
|
|
13
|
+
|
|
14
|
+
## 特性
|
|
15
|
+
|
|
16
|
+
- **类型安全** — 表单值、字段名称和验证的完整 TypeScript 推断
|
|
17
|
+
- **框架无关** — 支持 React、Vue、Angular 等
|
|
18
|
+
- **无头** — 无 UI 限制,使用你自己的组件
|
|
19
|
+
- **高性能** — 字段级订阅,无不必要的重渲染
|
|
20
|
+
- **验证** — 内置同步和异步验证,支持 Zod、Valibot 和 Yup 适配器
|
|
21
|
+
- **数组和动态字段** — 一流的数组字段支持
|
|
22
|
+
|
|
23
|
+
## 基本示例
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useForm } from '@tanstack/react-form'
|
|
27
|
+
|
|
28
|
+
function SignupForm() {
|
|
29
|
+
const form = useForm({
|
|
30
|
+
defaultValues: {
|
|
31
|
+
firstName: '',
|
|
32
|
+
lastName: '',
|
|
33
|
+
email: '',
|
|
34
|
+
},
|
|
35
|
+
onSubmit: async ({ value }) => {
|
|
36
|
+
console.log(value)
|
|
37
|
+
},
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<form
|
|
42
|
+
onSubmit={(e) => {
|
|
43
|
+
e.preventDefault()
|
|
44
|
+
form.handleSubmit()
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
<form.Field
|
|
48
|
+
name="firstName"
|
|
49
|
+
validators={{
|
|
50
|
+
onChange: ({ value }) =>
|
|
51
|
+
!value ? 'First name is required' : undefined,
|
|
52
|
+
}}
|
|
53
|
+
>
|
|
54
|
+
{(field) => (
|
|
55
|
+
<div>
|
|
56
|
+
<label>First Name</label>
|
|
57
|
+
<input
|
|
58
|
+
value={field.state.value}
|
|
59
|
+
onChange={(e) => field.handleChange(e.target.value)}
|
|
60
|
+
/>
|
|
61
|
+
{field.state.meta.errors.length > 0 && (
|
|
62
|
+
<span>{field.state.meta.errors.join(', ')}</span>
|
|
63
|
+
)}
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
</form.Field>
|
|
67
|
+
<button type="submit">Submit</button>
|
|
68
|
+
</form>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"sections": [
|
|
3
|
+
{
|
|
4
|
+
"label": "Getting Started",
|
|
5
|
+
"children": [
|
|
6
|
+
{ "label": "Overview", "to": "overview" },
|
|
7
|
+
{ "label": "Installation", "to": "installation" },
|
|
8
|
+
{ "label": "Quick Start", "to": "quick-start" }
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"label": "Guides",
|
|
13
|
+
"children": [
|
|
14
|
+
{ "label": "Queries", "to": "guides/queries" },
|
|
15
|
+
{ "label": "Pagination", "to": "guides/pagination" },
|
|
16
|
+
{ "label": "Mutations", "to": "guides/mutations" }
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"label": "React",
|
|
21
|
+
"frameworks": [
|
|
22
|
+
{
|
|
23
|
+
"label": "React",
|
|
24
|
+
"children": [
|
|
25
|
+
{ "label": "Overview", "to": "overview" },
|
|
26
|
+
{ "label": "Quick Start", "to": "quick-start" }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Mutations
|
|
3
|
+
description: Learn how to create, update, and delete data with TanStack Query mutations
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Mutations
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
## Basic Mutation
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
14
|
+
|
|
15
|
+
function AddTodo() {
|
|
16
|
+
const queryClient = useQueryClient()
|
|
17
|
+
|
|
18
|
+
const mutation = useMutation({
|
|
19
|
+
mutationFn: (newTodo: { title: string }) => {
|
|
20
|
+
return fetch('/api/todos', {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
body: JSON.stringify(newTodo),
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
}).then((res) => res.json())
|
|
25
|
+
},
|
|
26
|
+
onSuccess: () => {
|
|
27
|
+
// Invalidate and refetch the todos list
|
|
28
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<button
|
|
34
|
+
onClick={() => mutation.mutate({ title: 'New Todo' })}
|
|
35
|
+
disabled={mutation.isPending}
|
|
36
|
+
>
|
|
37
|
+
{mutation.isPending ? 'Adding...' : 'Add Todo'}
|
|
38
|
+
</button>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Mutation States
|
|
44
|
+
|
|
45
|
+
A mutation can only be in one of the following states at any given moment:
|
|
46
|
+
|
|
47
|
+
| State | Description |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `isIdle` | The mutation is idle or in a fresh/reset state |
|
|
50
|
+
| `isPending` | The mutation is currently running |
|
|
51
|
+
| `isError` | The mutation encountered an error |
|
|
52
|
+
| `isSuccess` | The mutation was successful and data is available |
|
|
53
|
+
|
|
54
|
+
## Optimistic Updates
|
|
55
|
+
|
|
56
|
+
Optimistic updates allow you to update the UI before the server confirms the mutation, providing a snappier user experience:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
const mutation = useMutation({
|
|
60
|
+
mutationFn: updateTodo,
|
|
61
|
+
onMutate: async (newTodo) => {
|
|
62
|
+
// Cancel any outgoing refetches to avoid overwriting optimistic update
|
|
63
|
+
await queryClient.cancelQueries({ queryKey: ['todos'] })
|
|
64
|
+
|
|
65
|
+
// Snapshot the previous value
|
|
66
|
+
const previousTodos = queryClient.getQueryData(['todos'])
|
|
67
|
+
|
|
68
|
+
// Optimistically update to the new value
|
|
69
|
+
queryClient.setQueryData(['todos'], (old: Todo[]) => [
|
|
70
|
+
...old,
|
|
71
|
+
{ ...newTodo, id: Date.now() },
|
|
72
|
+
])
|
|
73
|
+
|
|
74
|
+
// Return a context object with the snapshotted value
|
|
75
|
+
return { previousTodos }
|
|
76
|
+
},
|
|
77
|
+
onError: (_err, _newTodo, context) => {
|
|
78
|
+
// Roll back to the previous value on error
|
|
79
|
+
queryClient.setQueryData(['todos'], context?.previousTodos)
|
|
80
|
+
},
|
|
81
|
+
onSettled: () => {
|
|
82
|
+
// Always refetch after error or success
|
|
83
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
> [!NOTE]
|
|
89
|
+
> The `onMutate` handler runs before the mutation function and receives the same variables. It is the perfect place to perform optimistic updates.
|
|
90
|
+
|
|
91
|
+
## Retry
|
|
92
|
+
|
|
93
|
+
By default, TanStack Query will not retry failed mutations. You can configure this per-mutation:
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
const mutation = useMutation({
|
|
97
|
+
mutationFn: addTodo,
|
|
98
|
+
retry: 3, // Retry failed mutations 3 times
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Mutation Callbacks
|
|
103
|
+
|
|
104
|
+
The `useMutation` hook supports several callback options:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
useMutation({
|
|
108
|
+
mutationFn: addTodo,
|
|
109
|
+
onMutate: (variables) => {
|
|
110
|
+
// Called before the mutation function fires
|
|
111
|
+
// Receives the same variables the mutation function would receive
|
|
112
|
+
},
|
|
113
|
+
onError: (error, variables, context) => {
|
|
114
|
+
// Called if the mutation encounters an error
|
|
115
|
+
},
|
|
116
|
+
onSuccess: (data, variables, context) => {
|
|
117
|
+
// Called if the mutation is successful
|
|
118
|
+
},
|
|
119
|
+
onSettled: (data, error, variables, context) => {
|
|
120
|
+
// Called regardless of success or error
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> [!WARNING]
|
|
126
|
+
> The callbacks on `useMutation` fire for every component instance that uses it. To ensure side-effects only run once, use the callbacks on the `mutate` function or move the mutation to a shared hook.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pagination
|
|
3
|
+
description: Learn how to implement paginated queries with TanStack Query
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Pagination
|
|
7
|
+
|
|
8
|
+
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.
|
|
9
|
+
|
|
10
|
+
## Basic Pagination Example
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
const fetchProjects = async (page: number) => {
|
|
14
|
+
const res = await fetch(`/api/projects?page=${page}`)
|
|
15
|
+
return res.json()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function Projects() {
|
|
19
|
+
const [page, setPage] = React.useState(1)
|
|
20
|
+
|
|
21
|
+
const { data, isPreviousData, isLoading } = useQuery({
|
|
22
|
+
queryKey: ['projects', page],
|
|
23
|
+
queryFn: () => fetchProjects(page),
|
|
24
|
+
placeholderData: keepPreviousData,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div>
|
|
29
|
+
{isLoading ? (
|
|
30
|
+
<div>Loading...</div>
|
|
31
|
+
) : (
|
|
32
|
+
<>
|
|
33
|
+
{data.projects.map((project) => (
|
|
34
|
+
<p key={project.id}>{project.name}</p>
|
|
35
|
+
))}
|
|
36
|
+
</>
|
|
37
|
+
)}
|
|
38
|
+
<div className="flex gap-2">
|
|
39
|
+
<button
|
|
40
|
+
onClick={() => setPage((old) => Math.max(old - 1, 1))}
|
|
41
|
+
disabled={page === 1}
|
|
42
|
+
>
|
|
43
|
+
Previous
|
|
44
|
+
</button>
|
|
45
|
+
<span>Page {page}</span>
|
|
46
|
+
<button
|
|
47
|
+
onClick={() => {
|
|
48
|
+
if (!isPreviousData && data.hasMore) {
|
|
49
|
+
setPage((old) => old + 1)
|
|
50
|
+
}
|
|
51
|
+
}}
|
|
52
|
+
disabled={isPreviousData || !data?.hasMore}
|
|
53
|
+
>
|
|
54
|
+
Next
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Using `keepPreviousData`
|
|
63
|
+
|
|
64
|
+
The `keepPreviousData` option is crucial for smooth pagination. When enabled, the data from the last successful fetch is available while new data is being requested, even when the query key changes.
|
|
65
|
+
|
|
66
|
+
> [!NOTE]
|
|
67
|
+
> `keepPreviousData` was renamed from `previousData` in v5. If you are migrating from v4, update your code accordingly.
|
|
68
|
+
|
|
69
|
+
## Prefetching Next Pages
|
|
70
|
+
|
|
71
|
+
For an even smoother UX, you can prefetch the next page before the user navigates to it:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
const queryClient = useQueryClient()
|
|
75
|
+
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
if (data?.hasMore) {
|
|
78
|
+
queryClient.prefetchQuery({
|
|
79
|
+
queryKey: ['projects', page + 1],
|
|
80
|
+
queryFn: () => fetchProjects(page + 1),
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}, [data, page, queryClient])
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Infinite Queries
|
|
87
|
+
|
|
88
|
+
For "load more" and infinite scroll patterns, TanStack Query provides the `useInfiniteQuery` hook. See the [Infinite Queries guide](/en/query/docs/guides/infinite-queries) for details.
|
|
89
|
+
|
|
90
|
+
| Feature | `useQuery` + pagination | `useInfiniteQuery` |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| Page navigation | Previous / Next buttons | Load More / Infinite Scroll |
|
|
93
|
+
| Data structure | Single page | Accumulated pages |
|
|
94
|
+
| Memory usage | Lower (one page) | Higher (all loaded pages) |
|
|
95
|
+
| URL sync | Easy | More complex |
|
|
96
|
+
|
|
97
|
+
> [!WARNING]
|
|
98
|
+
> Do not use `useInfiniteQuery` for traditional page-based navigation. It is designed for "load more" patterns where previously loaded data stays visible.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Queries
|
|
3
|
+
description: Learn how queries work in TanStack Query
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Queries
|
|
7
|
+
|
|
8
|
+
A query is a declarative dependency on an asynchronous source of data that is tied to a unique key. A query can be used with any Promise-based method (including GET and POST methods) to fetch data from a server.
|
|
9
|
+
|
|
10
|
+
## Query Basics
|
|
11
|
+
|
|
12
|
+
To subscribe to a query in your components, call the query hook with at least a unique key and a function that returns a promise:
|
|
13
|
+
|
|
14
|
+
<!-- ::start:react -->
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { useQuery } from '@tanstack/react-query'
|
|
18
|
+
|
|
19
|
+
function Example() {
|
|
20
|
+
const { data, isLoading, error } = useQuery({
|
|
21
|
+
queryKey: ['todos'],
|
|
22
|
+
queryFn: fetchTodoList,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
<!-- ::end:react -->
|
|
28
|
+
|
|
29
|
+
<!-- ::start:vue -->
|
|
30
|
+
|
|
31
|
+
```vue
|
|
32
|
+
<script setup>
|
|
33
|
+
import { useQuery } from '@tanstack/vue-query'
|
|
34
|
+
|
|
35
|
+
const { data, isLoading, error } = useQuery({
|
|
36
|
+
queryKey: ['todos'],
|
|
37
|
+
queryFn: fetchTodoList,
|
|
38
|
+
})
|
|
39
|
+
</script>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<!-- ::end:vue -->
|
|
43
|
+
|
|
44
|
+
<!-- ::start:solid -->
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { createQuery } from '@tanstack/solid-query'
|
|
48
|
+
|
|
49
|
+
function Example() {
|
|
50
|
+
const query = createQuery(() => ({
|
|
51
|
+
queryKey: ['todos'],
|
|
52
|
+
queryFn: fetchTodoList,
|
|
53
|
+
}))
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
<!-- ::end:solid -->
|
|
58
|
+
|
|
59
|
+
## Query Keys
|
|
60
|
+
|
|
61
|
+
Query keys are used to uniquely identify a query. They can be as simple as a string, or as complex as an array of many strings and nested objects:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// A simple string key
|
|
65
|
+
useQuery({ queryKey: ['todos'], ... })
|
|
66
|
+
|
|
67
|
+
// A key with variables
|
|
68
|
+
useQuery({ queryKey: ['todo', todoId], ... })
|
|
69
|
+
|
|
70
|
+
// A key with an object
|
|
71
|
+
useQuery({ queryKey: ['todos', { type: 'done', page: 1 }], ... })
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Query Functions
|
|
75
|
+
|
|
76
|
+
A query function can be literally any function that returns a promise. The promise that is returned should either resolve the data or throw an error:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const { data } = useQuery({
|
|
80
|
+
queryKey: ['todos'],
|
|
81
|
+
queryFn: async () => {
|
|
82
|
+
const response = await fetch('/api/todos')
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
throw new Error('Network response was not ok')
|
|
85
|
+
}
|
|
86
|
+
return response.json()
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Query States
|
|
92
|
+
|
|
93
|
+
A query can be in one of the following states at any given moment:
|
|
94
|
+
|
|
95
|
+
- **`isPending`** — The query has no data yet
|
|
96
|
+
- **`isError`** — The query encountered an error
|
|
97
|
+
- **`isSuccess`** — The query was successful and data is available
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
function Todos() {
|
|
101
|
+
const { data, isPending, isError, error } = useQuery({
|
|
102
|
+
queryKey: ['todos'],
|
|
103
|
+
queryFn: fetchTodos,
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
if (isPending) return <span>Loading...</span>
|
|
107
|
+
if (isError) return <span>Error: {error.message}</span>
|
|
108
|
+
|
|
109
|
+
return (
|
|
110
|
+
<ul>
|
|
111
|
+
{data.map((todo) => (
|
|
112
|
+
<li key={todo.id}>{todo.title}</li>
|
|
113
|
+
))}
|
|
114
|
+
</ul>
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> [!NOTE]
|
|
120
|
+
> In TanStack Query v5, `isLoading` has been renamed to `isPending` for consistency.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: How to install TanStack Query in your project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
|
|
8
|
+
TanStack Query is available as a package on npm for each supported framework.
|
|
9
|
+
|
|
10
|
+
## Install the Package
|
|
11
|
+
|
|
12
|
+
Choose the package for your framework:
|
|
13
|
+
|
|
14
|
+
### React
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @tanstack/react-query
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pnpm add @tanstack/react-query
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
yarn add @tanstack/react-query
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
bun add @tanstack/react-query
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Vue
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install @tanstack/vue-query
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Solid
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install @tanstack/solid-query
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Svelte
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm install @tanstack/svelte-query
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Angular
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm install @tanstack/angular-query-experimental
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Requirements
|
|
57
|
+
|
|
58
|
+
- TypeScript 4.7+ (for type inference)
|
|
59
|
+
- React 18+ / Vue 3+ / Solid 1.6+ / Svelte 4+
|
|
60
|
+
|
|
61
|
+
## Devtools
|
|
62
|
+
|
|
63
|
+
We recommend also installing the devtools for a better development experience:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install @tanstack/react-query-devtools
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> Devtools are currently only available for React. Community devtools exist for other frameworks.
|
|
71
|
+
|
|
72
|
+
## CDN
|
|
73
|
+
|
|
74
|
+
For prototyping, you can load TanStack Query from a CDN:
|
|
75
|
+
|
|
76
|
+
```html
|
|
77
|
+
<script src="https://unpkg.com/@tanstack/react-query/build/umd/index.production.js"></script>
|
|
78
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TanStack Query Overview
|
|
3
|
+
description: Powerful asynchronous state management for TS/JS, React, Vue, Solid, Svelte & Angular
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TanStack Query
|
|
7
|
+
|
|
8
|
+
TanStack Query (formerly React Query) makes fetching, caching, synchronizing, and updating server state in your web applications a breeze.
|
|
9
|
+
|
|
10
|
+
## Motivation
|
|
11
|
+
|
|
12
|
+
Most core web frameworks do not come with an opinionated way of fetching or updating data in a holistic way. Developers end up building either meta-frameworks which encapsulate strict opinions about data-fetching, or they invent their own ways of fetching data. This usually means cobbling together component-based state and side-effects, or using more general purpose state management libraries to store and provide asynchronous data throughout their apps.
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **Transport/protocol/backend agnostic** data fetching (REST, GraphQL, promises, whatever!)
|
|
17
|
+
- **Auto Caching** with request deduplication
|
|
18
|
+
- **Automatic Refetching** with stale-while-revalidate strategy
|
|
19
|
+
- **Window Focus Refetching** to keep data current
|
|
20
|
+
- **Polling/Realtime** queries with configurable intervals
|
|
21
|
+
- **Parallel & Dependent Queries** for complex data requirements
|
|
22
|
+
- **Mutations** with optimistic updates
|
|
23
|
+
- **Pagination & Infinite Scroll** out of the box
|
|
24
|
+
- **Dedicated Devtools** for debugging
|
|
25
|
+
|
|
26
|
+
## Supported Frameworks
|
|
27
|
+
|
|
28
|
+
TanStack Query supports the following frameworks:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
// React
|
|
32
|
+
import { useQuery } from '@tanstack/react-query'
|
|
33
|
+
|
|
34
|
+
// Vue
|
|
35
|
+
import { useQuery } from '@tanstack/vue-query'
|
|
36
|
+
|
|
37
|
+
// Solid
|
|
38
|
+
import { createQuery } from '@tanstack/solid-query'
|
|
39
|
+
|
|
40
|
+
// Svelte
|
|
41
|
+
import { createQuery } from '@tanstack/svelte-query'
|
|
42
|
+
|
|
43
|
+
// Angular
|
|
44
|
+
import { injectQuery } from '@tanstack/angular-query-experimental'
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Example
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import { useQuery } from '@tanstack/react-query'
|
|
51
|
+
|
|
52
|
+
function App() {
|
|
53
|
+
const { data, isLoading, error } = useQuery({
|
|
54
|
+
queryKey: ['todos'],
|
|
55
|
+
queryFn: () => fetch('/api/todos').then(res => res.json()),
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
if (isLoading) return <div>Loading...</div>
|
|
59
|
+
if (error) return <div>Error: {error.message}</div>
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<ul>
|
|
63
|
+
{data.map(todo => (
|
|
64
|
+
<li key={todo.id}>{todo.title}</li>
|
|
65
|
+
))}
|
|
66
|
+
</ul>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> [!NOTE]
|
|
72
|
+
> TanStack Query v5 is the latest version and includes significant improvements over v4 including a simplified API and better TypeScript support.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quick Start
|
|
3
|
+
description: Get up and running with TanStack Query in minutes
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Quick Start
|
|
7
|
+
|
|
8
|
+
This guide will help you get started with TanStack Query as quickly as possible.
|
|
9
|
+
|
|
10
|
+
## Set Up the Provider
|
|
11
|
+
|
|
12
|
+
Wrap your application with `QueryClientProvider` and pass a `QueryClient` instance:
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
16
|
+
|
|
17
|
+
const queryClient = new QueryClient()
|
|
18
|
+
|
|
19
|
+
function App() {
|
|
20
|
+
return (
|
|
21
|
+
<QueryClientProvider client={queryClient}>
|
|
22
|
+
<MyApp />
|
|
23
|
+
</QueryClientProvider>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Your First Query
|
|
29
|
+
|
|
30
|
+
Use the `useQuery` hook to fetch data:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
import { useQuery } from '@tanstack/react-query'
|
|
34
|
+
|
|
35
|
+
function Todos() {
|
|
36
|
+
const { data, isLoading, error } = useQuery({
|
|
37
|
+
queryKey: ['todos'],
|
|
38
|
+
queryFn: fetchTodos,
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (isLoading) return <span>Loading...</span>
|
|
42
|
+
if (error) return <span>Error: {error.message}</span>
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<ul>
|
|
46
|
+
{data.map((todo) => (
|
|
47
|
+
<li key={todo.id}>{todo.title}</li>
|
|
48
|
+
))}
|
|
49
|
+
</ul>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function fetchTodos() {
|
|
54
|
+
const res = await fetch('https://jsonplaceholder.typicode.com/todos')
|
|
55
|
+
if (!res.ok) throw new Error('Failed to fetch')
|
|
56
|
+
return res.json()
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Your First Mutation
|
|
61
|
+
|
|
62
|
+
Use `useMutation` to create, update, or delete data:
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
|
66
|
+
|
|
67
|
+
function AddTodo() {
|
|
68
|
+
const queryClient = useQueryClient()
|
|
69
|
+
|
|
70
|
+
const mutation = useMutation({
|
|
71
|
+
mutationFn: (newTodo: { title: string }) =>
|
|
72
|
+
fetch('/api/todos', {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
body: JSON.stringify(newTodo),
|
|
75
|
+
}).then((res) => res.json()),
|
|
76
|
+
onSuccess: () => {
|
|
77
|
+
// Invalidate and refetch
|
|
78
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<button onClick={() => mutation.mutate({ title: 'New Todo' })}>
|
|
84
|
+
Add Todo
|
|
85
|
+
</button>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Adding Devtools
|
|
91
|
+
|
|
92
|
+
Add the React Query Devtools for debugging:
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
|
96
|
+
|
|
97
|
+
function App() {
|
|
98
|
+
return (
|
|
99
|
+
<QueryClientProvider client={queryClient}>
|
|
100
|
+
<MyApp />
|
|
101
|
+
<ReactQueryDevtools initialIsOpen={false} />
|
|
102
|
+
</QueryClientProvider>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
> [!NOTE]
|
|
108
|
+
> Devtools are automatically excluded from production builds.
|