@tanstack/router-core 1.168.0 → 1.168.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/router-core",
|
|
3
|
-
"version": "1.168.
|
|
3
|
+
"version": "1.168.1",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"@tanstack/history": "1.161.6"
|
|
156
156
|
},
|
|
157
157
|
"devDependencies": {
|
|
158
|
-
"@tanstack/store": "^0.9.
|
|
158
|
+
"@tanstack/store": "^0.9.2",
|
|
159
159
|
"@tanstack/intent": "^0.0.14",
|
|
160
160
|
"esbuild": "^0.27.4",
|
|
161
161
|
"vite": "*"
|
|
@@ -23,7 +23,7 @@ sources:
|
|
|
23
23
|
|
|
24
24
|
TanStack Router treats search params as JSON-first application state. They are automatically parsed from the URL into structured objects (numbers, booleans, arrays, nested objects) and validated via `validateSearch` on each route.
|
|
25
25
|
|
|
26
|
-
> **CRITICAL**: When using `zodValidator()
|
|
26
|
+
> **CRITICAL**: When using `zodValidator()` and Zod v3, use `fallback()` from `@tanstack/zod-adapter`, NOT zod's `.catch()`. Using `.catch()` with the zod adapter makes the output type `unknown`, destroying type safety. This does not apply to Valibot or ArkType (which use their own fallback mechanisms). It also does not apply to Zod v4, which should use `.catch()` and not use the `zodValidator()`.
|
|
27
27
|
> **CRITICAL**: Types are fully inferred. Never annotate the return of `useSearch()`.
|
|
28
28
|
|
|
29
29
|
## Setup: Zod Adapter (Recommended)
|
|
@@ -35,19 +35,16 @@ npm install zod @tanstack/zod-adapter
|
|
|
35
35
|
```tsx
|
|
36
36
|
// src/routes/products.tsx
|
|
37
37
|
import { createFileRoute } from '@tanstack/react-router'
|
|
38
|
-
import { zodValidator, fallback } from '@tanstack/zod-adapter'
|
|
39
38
|
import { z } from 'zod'
|
|
40
39
|
|
|
41
40
|
const productSearchSchema = z.object({
|
|
42
|
-
page:
|
|
43
|
-
filter:
|
|
44
|
-
sort:
|
|
45
|
-
'newest',
|
|
46
|
-
),
|
|
41
|
+
page: z.number().default(1).catch(1),
|
|
42
|
+
filter: z.string().default(''),
|
|
43
|
+
sort: z.enum(['newest', 'oldest', 'price']).default('newest').catch('newest'),
|
|
47
44
|
})
|
|
48
45
|
|
|
49
46
|
export const Route = createFileRoute('/products')({
|
|
50
|
-
validateSearch:
|
|
47
|
+
validateSearch: productSearchSchema,
|
|
51
48
|
component: ProductsPage,
|
|
52
49
|
})
|
|
53
50
|
|
|
@@ -168,15 +165,14 @@ Parent route search params are automatically merged into child routes:
|
|
|
168
165
|
```tsx
|
|
169
166
|
// src/routes/shop.tsx — parent defines shared params
|
|
170
167
|
import { createFileRoute } from '@tanstack/react-router'
|
|
171
|
-
import { zodValidator, fallback } from '@tanstack/zod-adapter'
|
|
172
168
|
import { z } from 'zod'
|
|
173
169
|
|
|
174
170
|
const shopSearchSchema = z.object({
|
|
175
|
-
currency:
|
|
171
|
+
currency: z.enum(['USD', 'EUR']).default('USD').catch('USD'),
|
|
176
172
|
})
|
|
177
173
|
|
|
178
174
|
export const Route = createFileRoute('/shop')({
|
|
179
|
-
validateSearch:
|
|
175
|
+
validateSearch: shopSearchSchema,
|
|
180
176
|
})
|
|
181
177
|
```
|
|
182
178
|
|
|
@@ -201,7 +197,6 @@ function ShopProducts() {
|
|
|
201
197
|
|
|
202
198
|
```tsx
|
|
203
199
|
import { createRootRoute, retainSearchParams } from '@tanstack/react-router'
|
|
204
|
-
import { zodValidator } from '@tanstack/zod-adapter'
|
|
205
200
|
import { z } from 'zod'
|
|
206
201
|
|
|
207
202
|
const rootSearchSchema = z.object({
|
|
@@ -209,7 +204,7 @@ const rootSearchSchema = z.object({
|
|
|
209
204
|
})
|
|
210
205
|
|
|
211
206
|
export const Route = createRootRoute({
|
|
212
|
-
validateSearch:
|
|
207
|
+
validateSearch: rootSearchSchema,
|
|
213
208
|
search: {
|
|
214
209
|
middlewares: [retainSearchParams(['debug'])],
|
|
215
210
|
},
|
|
@@ -220,7 +215,6 @@ export const Route = createRootRoute({
|
|
|
220
215
|
|
|
221
216
|
```tsx
|
|
222
217
|
import { createFileRoute, stripSearchParams } from '@tanstack/react-router'
|
|
223
|
-
import { zodValidator } from '@tanstack/zod-adapter'
|
|
224
218
|
import { z } from 'zod'
|
|
225
219
|
|
|
226
220
|
const defaults = { sort: 'newest', page: 1 }
|
|
@@ -231,7 +225,7 @@ const searchSchema = z.object({
|
|
|
231
225
|
})
|
|
232
226
|
|
|
233
227
|
export const Route = createFileRoute('/items')({
|
|
234
|
-
validateSearch:
|
|
228
|
+
validateSearch: searchSchema,
|
|
235
229
|
search: {
|
|
236
230
|
middlewares: [stripSearchParams(defaults)],
|
|
237
231
|
},
|
|
@@ -242,13 +236,11 @@ export const Route = createFileRoute('/items')({
|
|
|
242
236
|
|
|
243
237
|
```tsx
|
|
244
238
|
export const Route = createFileRoute('/search')({
|
|
245
|
-
validateSearch:
|
|
246
|
-
z.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}),
|
|
251
|
-
),
|
|
239
|
+
validateSearch: z.object({
|
|
240
|
+
retainMe: z.string().optional(),
|
|
241
|
+
arrayWithDefaults: z.string().array().default(['foo', 'bar']),
|
|
242
|
+
required: z.string(),
|
|
243
|
+
}),
|
|
252
244
|
search: {
|
|
253
245
|
middlewares: [
|
|
254
246
|
retainSearchParams(['retainMe']),
|
|
@@ -281,7 +273,7 @@ const router = createRouter({
|
|
|
281
273
|
|
|
282
274
|
```tsx
|
|
283
275
|
export const Route = createFileRoute('/products')({
|
|
284
|
-
validateSearch:
|
|
276
|
+
validateSearch: productSearchSchema,
|
|
285
277
|
// Pick ONLY the params the loader needs — not the entire search object
|
|
286
278
|
loaderDeps: ({ search }) => ({ page: search.page }),
|
|
287
279
|
loader: async ({ deps }) => {
|
|
@@ -292,7 +284,7 @@ export const Route = createFileRoute('/products')({
|
|
|
292
284
|
|
|
293
285
|
## Common Mistakes
|
|
294
286
|
|
|
295
|
-
### 1. HIGH: Using zod `.catch()` with `zodValidator()` instead of adapter `fallback()`
|
|
287
|
+
### 1. HIGH: Using zod v3's `.catch()` with `zodValidator()` instead of adapter `fallback()`
|
|
296
288
|
|
|
297
289
|
```tsx
|
|
298
290
|
// WRONG — .catch() with zodValidator makes the type unknown
|
|
@@ -304,6 +296,8 @@ import { fallback } from '@tanstack/zod-adapter'
|
|
|
304
296
|
const schema = z.object({ page: fallback(z.number(), 1) })
|
|
305
297
|
```
|
|
306
298
|
|
|
299
|
+
**Important:** This only applies when using Zod v3, not when using Zod v4. For v4, using `.catch()` is correct.
|
|
300
|
+
|
|
307
301
|
### 2. HIGH: Returning entire search object from `loaderDeps`
|
|
308
302
|
|
|
309
303
|
```tsx
|
|
@@ -335,7 +329,7 @@ export const Route = createRootRoute({
|
|
|
335
329
|
|
|
336
330
|
// CORRECT — parent must define validateSearch for children to inherit
|
|
337
331
|
export const Route = createRootRoute({
|
|
338
|
-
validateSearch:
|
|
332
|
+
validateSearch: globalSearchSchema,
|
|
339
333
|
component: RootComponent,
|
|
340
334
|
})
|
|
341
335
|
```
|