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.
Files changed (88) hide show
  1. package/admin/dist/server/server.js +32 -32
  2. package/package.json +1 -1
  3. package/template/app/routes/$lang.$project.$version.docs.$.tsx +2 -1
  4. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.$.tsx +2 -0
  5. package/template/app/routes/$lang.$project.$version.docs.tsx +2 -1
  6. package/template/app/routes/$lang.$project.docs.$.tsx +2 -1
  7. package/template/app/routes/$lang.$project.docs.tsx +2 -1
  8. package/template/app/routes/$lang.docs.$.tsx +2 -1
  9. package/template/app/routes/$lang.docs.framework.$framework.$.tsx +2 -0
  10. package/template/app/routes/$lang.docs.tsx +2 -1
  11. package/template/app/utils/content-loader.ts +13 -2
  12. package/template/app/utils/docs.server.ts +17 -15
  13. package/template/content/blog/en/announcing-query-v5.md +110 -0
  14. package/template/content/blog/en/hello-world.md +26 -0
  15. package/template/content/blog/en/i18n-best-practices.md +57 -0
  16. package/template/content/blog/en/react-query-vs-swr.md +100 -0
  17. package/template/content/blog/en/state-management-2024.md +143 -0
  18. package/template/content/blog/en/tanstack-router-1.0.md +121 -0
  19. package/template/content/blog/ja/announcing-query-v5.md +110 -0
  20. package/template/content/blog/ja/hello-world.md +26 -0
  21. package/template/content/blog/zh-hans/announcing-query-v5.md +93 -0
  22. package/template/content/blog/zh-hans/hello-world.md +26 -0
  23. package/template/content/docs-i18n/docs.config.json +25 -0
  24. package/template/content/docs-i18n/en/architecture.md +335 -0
  25. package/template/content/docs-i18n/en/cli.md +13 -1
  26. package/template/content/docs-i18n/en/configuration.md +350 -0
  27. package/template/content/docs-i18n/en/deployment.md +222 -0
  28. package/template/content/docs-i18n/en/getting-started.md +189 -0
  29. package/template/content/docs.config.json +25 -0
  30. package/template/content/en/admin.md +151 -0
  31. package/template/content/en/architecture.md +222 -0
  32. package/template/content/en/cli.md +269 -0
  33. package/template/content/en/configuration.md +331 -0
  34. package/template/content/en/deployment.md +209 -0
  35. package/template/content/en/getting-started.md +168 -0
  36. package/template/content/form/docs.config.json +18 -0
  37. package/template/content/form/en/guides/validation.md +175 -0
  38. package/template/content/form/en/installation.md +63 -0
  39. package/template/content/form/en/overview.md +71 -0
  40. package/template/content/form/en/quick-start.md +121 -0
  41. package/template/content/form/ja/installation.md +63 -0
  42. package/template/content/form/ja/overview.md +71 -0
  43. package/template/content/form/zh-hans/installation.md +63 -0
  44. package/template/content/form/zh-hans/overview.md +71 -0
  45. package/template/content/query/docs.config.json +32 -0
  46. package/template/content/query/en/guides/mutations.md +126 -0
  47. package/template/content/query/en/guides/pagination.md +98 -0
  48. package/template/content/query/en/guides/queries.md +120 -0
  49. package/template/content/query/en/installation.md +78 -0
  50. package/template/content/query/en/overview.md +72 -0
  51. package/template/content/query/en/quick-start.md +108 -0
  52. package/template/content/query/ja/installation.md +78 -0
  53. package/template/content/query/ja/overview.md +72 -0
  54. package/template/content/query/zh-hans/guides/mutations.md +126 -0
  55. package/template/content/query/zh-hans/guides/pagination.md +98 -0
  56. package/template/content/query/zh-hans/guides/queries.md +120 -0
  57. package/template/content/query/zh-hans/installation.md +95 -0
  58. package/template/content/query/zh-hans/overview.md +72 -0
  59. package/template/content/query/zh-hans/quick-start.md +108 -0
  60. package/template/content/router/docs.config.json +18 -0
  61. package/template/content/router/en/guides/routing-concepts.md +131 -0
  62. package/template/content/router/en/installation.md +57 -0
  63. package/template/content/router/en/overview.md +74 -0
  64. package/template/content/router/en/quick-start.md +88 -0
  65. package/template/content/router/ja/installation.md +57 -0
  66. package/template/content/router/ja/overview.md +78 -0
  67. package/template/content/router/zh-hans/guides/routing-concepts.md +131 -0
  68. package/template/content/router/zh-hans/installation.md +57 -0
  69. package/template/content/router/zh-hans/overview.md +81 -0
  70. package/template/content/router/zh-hans/quick-start.md +88 -0
  71. package/template/content/table/docs.config.json +18 -0
  72. package/template/content/table/en/guides/column-definitions.md +135 -0
  73. package/template/content/table/en/installation.md +56 -0
  74. package/template/content/table/en/overview.md +79 -0
  75. package/template/content/table/en/quick-start.md +112 -0
  76. package/template/content/table/ja/installation.md +56 -0
  77. package/template/content/table/ja/overview.md +79 -0
  78. package/template/content/table/zh-hans/installation.md +56 -0
  79. package/template/content/table/zh-hans/overview.md +79 -0
  80. package/template/content/virtual/docs.config.json +18 -0
  81. package/template/content/virtual/en/guides/dynamic-sizing.md +129 -0
  82. package/template/content/virtual/en/installation.md +57 -0
  83. package/template/content/virtual/en/overview.md +74 -0
  84. package/template/content/virtual/en/quick-start.md +114 -0
  85. package/template/content/virtual/ja/installation.md +57 -0
  86. package/template/content/virtual/ja/overview.md +74 -0
  87. package/template/content/virtual/zh-hans/installation.md +57 -0
  88. package/template/content/virtual/zh-hans/overview.md +74 -0
@@ -0,0 +1,121 @@
1
+ ---
2
+ title: Quick Start
3
+ description: Get up and running with TanStack Form
4
+ ---
5
+
6
+ # Quick Start
7
+
8
+ ## Create a Form
9
+
10
+ Use the `useForm` hook to create a form instance:
11
+
12
+ ```tsx
13
+ import { useForm } from '@tanstack/react-form'
14
+
15
+ function MyForm() {
16
+ const form = useForm({
17
+ defaultValues: {
18
+ username: '',
19
+ password: '',
20
+ },
21
+ onSubmit: async ({ value }) => {
22
+ // Handle form submission
23
+ await loginUser(value)
24
+ },
25
+ })
26
+
27
+ return (
28
+ <form
29
+ onSubmit={(e) => {
30
+ e.preventDefault()
31
+ form.handleSubmit()
32
+ }}
33
+ >
34
+ {/* Fields go here */}
35
+ <button type="submit">Submit</button>
36
+ </form>
37
+ )
38
+ }
39
+ ```
40
+
41
+ ## Add Fields
42
+
43
+ Use `form.Field` to create type-safe form fields:
44
+
45
+ ```tsx
46
+ <form.Field name="username">
47
+ {(field) => (
48
+ <div>
49
+ <label htmlFor={field.name}>Username</label>
50
+ <input
51
+ id={field.name}
52
+ value={field.state.value}
53
+ onBlur={field.handleBlur}
54
+ onChange={(e) => field.handleChange(e.target.value)}
55
+ />
56
+ </div>
57
+ )}
58
+ </form.Field>
59
+ ```
60
+
61
+ ## Add Validation
62
+
63
+ Add field-level validation with sync or async validators:
64
+
65
+ ```tsx
66
+ <form.Field
67
+ name="email"
68
+ validators={{
69
+ onChange: ({ value }) => {
70
+ if (!value) return 'Email is required'
71
+ if (!value.includes('@')) return 'Invalid email address'
72
+ return undefined
73
+ },
74
+ onChangeAsyncDebounceMs: 500,
75
+ onChangeAsync: async ({ value }) => {
76
+ const exists = await checkEmailExists(value)
77
+ return exists ? 'Email already taken' : undefined
78
+ },
79
+ }}
80
+ >
81
+ {(field) => (
82
+ <div>
83
+ <input
84
+ value={field.state.value}
85
+ onChange={(e) => field.handleChange(e.target.value)}
86
+ />
87
+ {field.state.meta.errors.map((error) => (
88
+ <p key={error} className="text-red-500">{error}</p>
89
+ ))}
90
+ </div>
91
+ )}
92
+ </form.Field>
93
+ ```
94
+
95
+ ## Using Zod Validation
96
+
97
+ ```tsx
98
+ import { zodValidator } from '@tanstack/zod-form-adapter'
99
+ import { z } from 'zod'
100
+
101
+ const form = useForm({
102
+ defaultValues: { email: '' },
103
+ validatorAdapter: zodValidator(),
104
+ onSubmit: async ({ value }) => {
105
+ console.log(value)
106
+ },
107
+ })
108
+
109
+ // Then in your field:
110
+ <form.Field
111
+ name="email"
112
+ validators={{
113
+ onChange: z.string().email('Invalid email'),
114
+ }}
115
+ >
116
+ {(field) => /* ... */}
117
+ </form.Field>
118
+ ```
119
+
120
+ > [!NOTE]
121
+ > Async validators support debouncing out of the box with `onChangeAsyncDebounceMs`.
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: インストール
3
+ description: プロジェクトに TanStack Form をインストールする方法
4
+ ---
5
+
6
+ # インストール
7
+
8
+ ## React
9
+
10
+ ```bash
11
+ npm install @tanstack/react-form
12
+ ```
13
+
14
+ ```bash
15
+ pnpm add @tanstack/react-form
16
+ ```
17
+
18
+ ```bash
19
+ yarn add @tanstack/react-form
20
+ ```
21
+
22
+ ```bash
23
+ bun add @tanstack/react-form
24
+ ```
25
+
26
+ ## Vue
27
+
28
+ ```bash
29
+ npm install @tanstack/vue-form
30
+ ```
31
+
32
+ ## Angular
33
+
34
+ ```bash
35
+ npm install @tanstack/angular-form
36
+ ```
37
+
38
+ ## バリデーションアダプター
39
+
40
+ TanStack Form はアダプターを通じて人気のバリデーションライブラリをサポートしています:
41
+
42
+ ### Zod
43
+
44
+ ```bash
45
+ npm install @tanstack/zod-form-adapter zod
46
+ ```
47
+
48
+ ### Valibot
49
+
50
+ ```bash
51
+ npm install @tanstack/valibot-form-adapter valibot
52
+ ```
53
+
54
+ ### Yup
55
+
56
+ ```bash
57
+ npm install @tanstack/yup-form-adapter yup
58
+ ```
59
+
60
+ ## 必要要件
61
+
62
+ - TypeScript 5.0+
63
+ - React 18+ / Vue 3+ / Angular 17+
@@ -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,63 @@
1
+ ---
2
+ title: 安装
3
+ description: 如何在项目中安装 TanStack Form
4
+ ---
5
+
6
+ # 安装
7
+
8
+ ## React
9
+
10
+ ```bash
11
+ npm install @tanstack/react-form
12
+ ```
13
+
14
+ ```bash
15
+ pnpm add @tanstack/react-form
16
+ ```
17
+
18
+ ```bash
19
+ yarn add @tanstack/react-form
20
+ ```
21
+
22
+ ```bash
23
+ bun add @tanstack/react-form
24
+ ```
25
+
26
+ ## Vue
27
+
28
+ ```bash
29
+ npm install @tanstack/vue-form
30
+ ```
31
+
32
+ ## Angular
33
+
34
+ ```bash
35
+ npm install @tanstack/angular-form
36
+ ```
37
+
38
+ ## 验证适配器
39
+
40
+ TanStack Form 通过适配器支持流行的验证库:
41
+
42
+ ### Zod
43
+
44
+ ```bash
45
+ npm install @tanstack/zod-form-adapter zod
46
+ ```
47
+
48
+ ### Valibot
49
+
50
+ ```bash
51
+ npm install @tanstack/valibot-form-adapter valibot
52
+ ```
53
+
54
+ ### Yup
55
+
56
+ ```bash
57
+ npm install @tanstack/yup-form-adapter yup
58
+ ```
59
+
60
+ ## 环境要求
61
+
62
+ - TypeScript 5.0+
63
+ - React 18+ / Vue 3+ / Angular 17+
@@ -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.