docs-i18n 0.8.1 → 0.8.3
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 +32 -32
- package/package.json +1 -1
- package/template/app/routes/$lang.$project.$version.docs.$.tsx +2 -1
- package/template/app/routes/$lang.$project.$version.docs.framework.$framework.$.tsx +2 -0
- package/template/app/routes/$lang.$project.$version.docs.tsx +2 -1
- package/template/app/routes/$lang.$project.docs.$.tsx +2 -1
- package/template/app/routes/$lang.$project.docs.tsx +2 -1
- package/template/app/routes/$lang.docs.$.tsx +2 -1
- package/template/app/routes/$lang.docs.framework.$framework.$.tsx +2 -0
- package/template/app/routes/$lang.docs.tsx +2 -1
- package/template/app/utils/content-loader.ts +13 -2
- package/template/app/utils/docs.server.ts +17 -15
- 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 +335 -0
- package/template/content/docs-i18n/en/cli.md +13 -1
- package/template/content/docs-i18n/en/configuration.md +350 -0
- package/template/content/docs-i18n/en/deployment.md +222 -0
- package/template/content/docs-i18n/en/getting-started.md +189 -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,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 分页
|
|
3
|
+
description: 了解如何使用 TanStack Query 实现分页查询
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 分页
|
|
7
|
+
|
|
8
|
+
渲染分页数据是非常常见的 UI 模式,在 TanStack Query 中,只需将页面信息包含在查询键中即可"自然生效"。
|
|
9
|
+
|
|
10
|
+
## 基本分页示例
|
|
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>加载中...</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
|
+
上一页
|
|
44
|
+
</button>
|
|
45
|
+
<span>第 {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
|
+
下一页
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 使用 `keepPreviousData`
|
|
63
|
+
|
|
64
|
+
`keepPreviousData` 选项对流畅的分页体验至关重要。启用后,即使查询键发生变化,在请求新数据时仍可使用上次成功获取的数据。
|
|
65
|
+
|
|
66
|
+
> [!NOTE]
|
|
67
|
+
> `keepPreviousData` 在 v5 中从 `previousData` 重命名而来。如果您是从 v4 迁移,请相应更新代码。
|
|
68
|
+
|
|
69
|
+
## 预取下一页
|
|
70
|
+
|
|
71
|
+
为了更流畅的用户体验,可以在用户导航之前预取下一页:
|
|
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
|
+
## 无限查询
|
|
87
|
+
|
|
88
|
+
对于"加载更多"和无限滚动模式,TanStack Query 提供了 `useInfiniteQuery` Hook。详情请参阅[无限查询指南](/en/query/docs/guides/infinite-queries)。
|
|
89
|
+
|
|
90
|
+
| 功能 | `useQuery` + 分页 | `useInfiniteQuery` |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| 页面导航 | 上一页/下一页按钮 | 加载更多/无限滚动 |
|
|
93
|
+
| 数据结构 | 单页 | 累积页面 |
|
|
94
|
+
| 内存使用 | 较低(一页) | 较高(所有已加载页面) |
|
|
95
|
+
| URL 同步 | 简单 | 更复杂 |
|
|
96
|
+
|
|
97
|
+
> [!WARNING]
|
|
98
|
+
> 不要将 `useInfiniteQuery` 用于传统的页面导航。它专为"加载更多"模式设计,即之前加载的数据保持可见。
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 查询
|
|
3
|
+
description: 了解 TanStack Query 中查询的工作原理
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 查询
|
|
7
|
+
|
|
8
|
+
查询是对异步数据源的声明式依赖,与唯一键绑定。查询可以与任何基于 Promise 的方法(包括 GET 和 POST 方法)一起使用,从服务器获取数据。
|
|
9
|
+
|
|
10
|
+
## 查询基础
|
|
11
|
+
|
|
12
|
+
要在组件中订阅查询,至少需要传入一个唯一键和一个返回 Promise 的函数来调用查询 Hook:
|
|
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
|
+
## 查询键
|
|
60
|
+
|
|
61
|
+
查询键用于唯一标识一个查询。它可以是一个简单的字符串,也可以是包含多个字符串和嵌套对象的数组:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// 简单字符串键
|
|
65
|
+
useQuery({ queryKey: ['todos'], ... })
|
|
66
|
+
|
|
67
|
+
// 带变量的键
|
|
68
|
+
useQuery({ queryKey: ['todo', todoId], ... })
|
|
69
|
+
|
|
70
|
+
// 带对象的键
|
|
71
|
+
useQuery({ queryKey: ['todos', { type: 'done', page: 1 }], ... })
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## 查询函数
|
|
75
|
+
|
|
76
|
+
查询函数可以是任何返回 Promise 的函数。返回的 Promise 应该解析数据或抛出错误:
|
|
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
|
+
## 查询状态
|
|
92
|
+
|
|
93
|
+
在任意时刻,查询可以处于以下状态之一:
|
|
94
|
+
|
|
95
|
+
- **`isPending`** — 查询尚无数据
|
|
96
|
+
- **`isError`** — 查询遇到错误
|
|
97
|
+
- **`isSuccess`** — 查询成功,数据可用
|
|
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>加载中...</span>
|
|
107
|
+
if (isError) return <span>错误:{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
|
+
> 在 TanStack Query v5 中,`isLoading` 已被重命名为 `isPending` 以保持一致性。
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 安装
|
|
3
|
+
description: 了解如何在项目中安装和配置 TanStack Query
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 安装
|
|
7
|
+
|
|
8
|
+
TanStack Query 兼容 React v18+,支持 ReactDOM 和 React Native。
|
|
9
|
+
|
|
10
|
+
## 安装依赖
|
|
11
|
+
|
|
12
|
+
使用你喜欢的包管理器安装:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @tanstack/react-query
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
或者使用其他包管理器:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# pnpm
|
|
22
|
+
pnpm add @tanstack/react-query
|
|
23
|
+
|
|
24
|
+
# yarn
|
|
25
|
+
yarn add @tanstack/react-query
|
|
26
|
+
|
|
27
|
+
# bun
|
|
28
|
+
bun add @tanstack/react-query
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 配置 QueryClient
|
|
32
|
+
|
|
33
|
+
在应用根组件中创建一个 `QueryClient` 实例,并用 `QueryClientProvider` 包裹应用:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
|
37
|
+
|
|
38
|
+
// 创建一个 QueryClient 实例
|
|
39
|
+
const queryClient = new QueryClient({
|
|
40
|
+
defaultOptions: {
|
|
41
|
+
queries: {
|
|
42
|
+
staleTime: 1000 * 60, // 1 分钟
|
|
43
|
+
retry: 1,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
function App() {
|
|
49
|
+
return (
|
|
50
|
+
<QueryClientProvider client={queryClient}>
|
|
51
|
+
<YourApp />
|
|
52
|
+
</QueryClientProvider>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 安装开发工具
|
|
58
|
+
|
|
59
|
+
开发工具有助于调试和可视化查询状态。推荐在开发环境中使用:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @tanstack/react-query-devtools
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
|
|
67
|
+
|
|
68
|
+
function App() {
|
|
69
|
+
return (
|
|
70
|
+
<QueryClientProvider client={queryClient}>
|
|
71
|
+
<YourApp />
|
|
72
|
+
<ReactQueryDevtools initialIsOpen={false} />
|
|
73
|
+
</QueryClientProvider>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> [!NOTE]
|
|
79
|
+
> 开发工具仅在开发环境中加载。在生产构建中会自动被 tree-shake 移除,不会增加生产包体积。
|
|
80
|
+
|
|
81
|
+
## TypeScript 配置
|
|
82
|
+
|
|
83
|
+
TanStack Query 使用 TypeScript 编写,开箱即用提供完整的类型支持。建议使用 TypeScript 4.7 或更高版本以获得最佳体验。
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"compilerOptions": {
|
|
88
|
+
"strict": true,
|
|
89
|
+
"moduleResolution": "bundler"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> [!WARNING]
|
|
95
|
+
> 请确保你的 TypeScript 版本不低于 4.7。旧版本可能无法正确推断某些类型。
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: TanStack Query 概述
|
|
3
|
+
description: 强大的异步状态管理,支持 TS/JS、React、Vue、Solid、Svelte 和 Angular
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TanStack Query
|
|
7
|
+
|
|
8
|
+
TanStack Query(前身为 React Query)让您在 Web 应用中轻松实现数据获取、缓存、同步和更新服务器状态。
|
|
9
|
+
|
|
10
|
+
## 动机
|
|
11
|
+
|
|
12
|
+
大多数核心 Web 框架并没有提供一套统一的数据获取或更新方案。开发者往往需要自己构建元框架来封装数据获取的逻辑,或者自行发明数据获取方式。这通常意味着将基于组件的状态和副作用拼凑在一起,或者使用通用的状态管理库来存储和提供异步数据。
|
|
13
|
+
|
|
14
|
+
## 特性
|
|
15
|
+
|
|
16
|
+
- **传输/协议/后端无关** 的数据获取(REST、GraphQL、Promise 等皆可!)
|
|
17
|
+
- **自动缓存** 并支持请求去重
|
|
18
|
+
- **自动重新获取** 采用 stale-while-revalidate 策略
|
|
19
|
+
- **窗口焦点重新获取** 保持数据最新
|
|
20
|
+
- **轮询/实时** 查询,可配置间隔
|
|
21
|
+
- **并行和依赖查询** 满足复杂数据需求
|
|
22
|
+
- **变更操作** 支持乐观更新
|
|
23
|
+
- **分页和无限滚动** 开箱即用
|
|
24
|
+
- **专用开发工具** 便于调试
|
|
25
|
+
|
|
26
|
+
## 支持的框架
|
|
27
|
+
|
|
28
|
+
TanStack Query 支持以下框架:
|
|
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
|
+
## 快速示例
|
|
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>加载中...</div>
|
|
59
|
+
if (error) return <div>错误:{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 是最新版本,包含大量改进,例如简化的 API 和更好的 TypeScript 支持。
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 快速开始
|
|
3
|
+
description: 几分钟内上手 TanStack Query
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 快速开始
|
|
7
|
+
|
|
8
|
+
本指南将帮助您尽快上手 TanStack Query。
|
|
9
|
+
|
|
10
|
+
## 设置 Provider
|
|
11
|
+
|
|
12
|
+
使用 `QueryClientProvider` 包裹您的应用,并传入一个 `QueryClient` 实例:
|
|
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
|
+
## 您的第一个查询
|
|
29
|
+
|
|
30
|
+
使用 `useQuery` Hook 来获取数据:
|
|
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>加载中...</span>
|
|
42
|
+
if (error) return <span>错误:{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
|
+
## 您的第一个变更操作
|
|
61
|
+
|
|
62
|
+
使用 `useMutation` 来创建、更新或删除数据:
|
|
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
|
+
// 使缓存失效并重新获取
|
|
78
|
+
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<button onClick={() => mutation.mutate({ title: 'New Todo' })}>
|
|
84
|
+
添加待办事项
|
|
85
|
+
</button>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 添加开发工具
|
|
91
|
+
|
|
92
|
+
添加 React Query Devtools 进行调试:
|
|
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
|
+
> 开发工具在生产构建中会自动排除。
|
|
@@ -0,0 +1,18 @@
|
|
|
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": "Routing Concepts", "to": "guides/routing-concepts" }
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Routing Concepts
|
|
3
|
+
description: Understand the core routing concepts in TanStack Router
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Routing Concepts
|
|
7
|
+
|
|
8
|
+
TanStack Router is built on a few core concepts that make it powerful and flexible. Understanding these concepts will help you build better applications.
|
|
9
|
+
|
|
10
|
+
## Route Trees
|
|
11
|
+
|
|
12
|
+
TanStack Router uses a route tree to define the structure of your application. Routes can be nested to create layouts and hierarchies:
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { createRootRoute, createRoute, createRouter } from '@tanstack/react-router'
|
|
16
|
+
|
|
17
|
+
const rootRoute = createRootRoute({
|
|
18
|
+
component: RootLayout,
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
const indexRoute = createRoute({
|
|
22
|
+
getParentRoute: () => rootRoute,
|
|
23
|
+
path: '/',
|
|
24
|
+
component: HomePage,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const aboutRoute = createRoute({
|
|
28
|
+
getParentRoute: () => rootRoute,
|
|
29
|
+
path: '/about',
|
|
30
|
+
component: AboutPage,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const routeTree = rootRoute.addChildren([indexRoute, aboutRoute])
|
|
34
|
+
|
|
35
|
+
const router = createRouter({ routeTree })
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## File-Based Routing
|
|
39
|
+
|
|
40
|
+
For most applications, TanStack Router supports file-based routing through a plugin. Your file structure becomes your route structure:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
app/
|
|
44
|
+
routes/
|
|
45
|
+
__root.tsx → Root layout
|
|
46
|
+
index.tsx → /
|
|
47
|
+
about.tsx → /about
|
|
48
|
+
posts.tsx → /posts (layout)
|
|
49
|
+
posts.index.tsx → /posts/
|
|
50
|
+
posts.$postId.tsx → /posts/:postId
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
> [!NOTE]
|
|
54
|
+
> File-based routing is powered by the `@tanstack/router-plugin` package, which generates the route tree automatically at build time.
|
|
55
|
+
|
|
56
|
+
## Search Params
|
|
57
|
+
|
|
58
|
+
TanStack Router treats search params as first-class citizens with full type safety:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
const productsRoute = createRoute({
|
|
62
|
+
getParentRoute: () => rootRoute,
|
|
63
|
+
path: '/products',
|
|
64
|
+
validateSearch: (search: Record<string, unknown>) => {
|
|
65
|
+
return {
|
|
66
|
+
page: Number(search.page) || 1,
|
|
67
|
+
filter: (search.filter as string) || '',
|
|
68
|
+
sort: (search.sort as 'asc' | 'desc') || 'asc',
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
component: ProductsPage,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
function ProductsPage() {
|
|
75
|
+
const { page, filter, sort } = productsRoute.useSearch()
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div>
|
|
79
|
+
<p>Page: {page}, Filter: {filter}, Sort: {sort}</p>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Data Loading
|
|
86
|
+
|
|
87
|
+
Routes can define loaders that fetch data before the route renders:
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
const postRoute = createRoute({
|
|
91
|
+
getParentRoute: () => postsRoute,
|
|
92
|
+
path: '$postId',
|
|
93
|
+
loader: async ({ params }) => {
|
|
94
|
+
const post = await fetchPost(params.postId)
|
|
95
|
+
return { post }
|
|
96
|
+
},
|
|
97
|
+
component: PostPage,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
function PostPage() {
|
|
101
|
+
const { post } = postRoute.useLoaderData()
|
|
102
|
+
return <article>{post.title}</article>
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Feature | Description |
|
|
107
|
+
|---|---|
|
|
108
|
+
| Route Trees | Hierarchical route definitions with parent-child relationships |
|
|
109
|
+
| File-Based Routing | Automatic route generation from file system |
|
|
110
|
+
| Search Params | Type-safe URL search parameters with validation |
|
|
111
|
+
| Data Loading | Pre-fetch data before route renders |
|
|
112
|
+
| Pending States | Built-in loading indicators during navigation |
|
|
113
|
+
| Error Boundaries | Per-route error handling |
|
|
114
|
+
|
|
115
|
+
## Path Params
|
|
116
|
+
|
|
117
|
+
Dynamic segments in the path are prefixed with `$`:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
// Single param
|
|
121
|
+
'/posts/$postId'
|
|
122
|
+
|
|
123
|
+
// Multiple params
|
|
124
|
+
'/users/$userId/posts/$postId'
|
|
125
|
+
|
|
126
|
+
// Splat/catch-all
|
|
127
|
+
'/files/$'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
> [!WARNING]
|
|
131
|
+
> Unlike some other routers, TanStack Router does not use `:` for dynamic segments. Always use `$` as the prefix.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Installation
|
|
3
|
+
description: How to install TanStack Router in your project
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Installation
|
|
7
|
+
|
|
8
|
+
## Install the Package
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @tanstack/react-router
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm add @tanstack/react-router
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
yarn add @tanstack/react-router
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add @tanstack/react-router
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Vite Plugin (Recommended)
|
|
27
|
+
|
|
28
|
+
For the best experience with file-based routing and automatic route generation, install the Vite plugin:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -D @tanstack/router-plugin
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then add it to your `vite.config.ts`:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { defineConfig } from 'vite'
|
|
38
|
+
import react from '@vitejs/plugin-react'
|
|
39
|
+
import { TanStackRouterVite } from '@tanstack/router-plugin/vite'
|
|
40
|
+
|
|
41
|
+
export default defineConfig({
|
|
42
|
+
plugins: [TanStackRouterVite(), react()],
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Devtools
|
|
47
|
+
|
|
48
|
+
Install the devtools for route debugging:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @tanstack/router-devtools
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
- React 18+
|
|
57
|
+
- TypeScript 5.0+ (strongly recommended)
|