pejay-ui 1.2.2 → 1.3.0
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 +1 -1
- package/registry.json +33 -1
- package/templates/notes/create-pejay.md +222 -0
- package/templates/notes/notes-v1.md +516 -0
- package/templates/notes/notes-v2.md +764 -0
- package/templates/notes/notes-v3.md +574 -0
- package/templates/notes/notes-v4.md +811 -0
- package/templates/notes/notes-v5.md +579 -0
- package/templates/notes/notes-vf+1.md +311 -0
- package/templates/notes/notes-vfinal.md +852 -0
- package/templates/scaffolds/axios/api/index.ts +40 -0
- package/templates/scaffolds/axios/api/one.api.ts +94 -0
- package/templates/scaffolds/axios/endpoints.ts +9 -0
- package/templates/scaffolds/axios/index.ts +26 -0
- package/templates/scaffolds/axios/interceptors.ts +103 -0
- package/templates/scaffolds/axios/request.ts +32 -0
- package/templates/scaffolds/react-router/hook/useRouterSearch.ts +8 -0
- package/templates/scaffolds/react-router/router/guards/private.route.tsx +1 -0
- package/templates/scaffolds/react-router/router/index.ts +26 -0
- package/templates/scaffolds/react-router/router/layouts/error.layout.tsx +1 -1
- package/templates/scaffolds/redux-store/middlewares.ts +0 -0
- package/templates/scaffolds/redux-store/reducers.ts +30 -0
- package/templates/scaffolds/redux-store/selector/one.selector.ts +43 -0
- package/templates/scaffolds/redux-store/selector/two.selector.ts +11 -0
- package/templates/scaffolds/redux-store/slices/one.slice.ts +202 -0
- package/templates/scaffolds/redux-store/slices/two.slice.ts +21 -0
- package/templates/scaffolds/redux-store/store.ts +38 -0
- package/templates/scaffolds/rtk-query/baseApi.ts +24 -0
- package/templates/scaffolds/rtk-query/baseQuery.ts +12 -0
- package/templates/scaffolds/rtk-query/endpoints/api.one.ts +82 -0
- package/templates/scaffolds/rtk-query/endpoints/index.ts +1 -0
- package/templates/scaffolds/rtk-query/middlewares.ts +11 -0
- package/templates/scaffolds/rtk-query/queryTags.ts +13 -0
- package/templates/scaffolds/tanstack-query/api-base.ts +68 -68
- package/templates/scaffolds/tanstack-query/api-queries.ts +0 -19
- package/templates/scaffolds/tanstack-query/client.ts +8 -0
- package/templates/scaffolds/tanstack-query/module/index.ts +12 -12
- package/templates/scaffolds/tanstack-query/module/keys.ts +17 -17
- package/templates/scaffolds/tanstack-query/module/mappers.ts +15 -15
- package/templates/scaffolds/tanstack-query/module/mutations.ts +59 -55
- package/templates/scaffolds/tanstack-query/module/queries.ts +145 -156
- package/templates/scaffolds/tanstack-query/module/services.ts +74 -66
- package/templates/scaffolds/tanstack-router/layout/404.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/layout/app.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/auth.layout.tsx +10 -0
- package/templates/scaffolds/tanstack-router/layout/error.layout.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/auth/login.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/index.tsx +3 -0
- package/templates/scaffolds/tanstack-router/page/one/one-id.tsx +128 -0
- package/templates/scaffolds/tanstack-router/router.ts +90 -0
- package/templates/scaffolds/tanstack-router/routes/_404.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/__root.tsx +9 -0
- package/templates/scaffolds/tanstack-router/routes/_app.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_auth.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/_error.tsx +0 -0
- package/templates/scaffolds/tanstack-router/routes/auth/login.tsx +6 -0
- package/templates/scaffolds/tanstack-router/routes/one/$id.tsx +191 -0
- package/templates/scaffolds/tanstack-router/routes/one/index.tsx +6 -0
- package/templates/scripts/setup.bat +284 -0
- package/templates/scripts/setup.ps1 +318 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
# TanStack Router - Advanced Features & Overlooked APIs
|
|
2
|
+
|
|
3
|
+
This document covers TanStack Router features that are often missed during the initial learning phase but become extremely valuable in medium-to-large applications.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 1. beforeLoad()
|
|
8
|
+
|
|
9
|
+
One of the most important TanStack Router features.
|
|
10
|
+
|
|
11
|
+
Runs before:
|
|
12
|
+
|
|
13
|
+
```txt
|
|
14
|
+
Component Render
|
|
15
|
+
Loader Execution
|
|
16
|
+
Route Entry
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
export const Route = createFileRoute("/_app")({
|
|
23
|
+
beforeLoad: ({ context }) => {
|
|
24
|
+
if (!context.auth.isAuthenticated) {
|
|
25
|
+
throw redirect({
|
|
26
|
+
to: "/login",
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Common Uses
|
|
36
|
+
|
|
37
|
+
```txt
|
|
38
|
+
Authentication
|
|
39
|
+
Authorization
|
|
40
|
+
Feature Flags
|
|
41
|
+
Role Checks
|
|
42
|
+
Tenant Validation
|
|
43
|
+
Subscription Checks
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Benefits
|
|
49
|
+
|
|
50
|
+
```txt
|
|
51
|
+
✓ Prevents unnecessary API calls
|
|
52
|
+
✓ Prevents component mounting
|
|
53
|
+
✓ Centralized access control
|
|
54
|
+
✓ Better than component-level guards
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
# 2. createRootRouteWithContext()
|
|
60
|
+
|
|
61
|
+
Provides globally typed router context.
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
interface RouterContext {
|
|
67
|
+
auth: AuthStore;
|
|
68
|
+
queryClient: QueryClient;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Root Route:
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
export const Route =
|
|
76
|
+
createRootRouteWithContext<
|
|
77
|
+
RouterContext
|
|
78
|
+
>()({
|
|
79
|
+
component: RootLayout,
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Why Use It?
|
|
86
|
+
|
|
87
|
+
Provides type-safe access to:
|
|
88
|
+
|
|
89
|
+
```txt
|
|
90
|
+
Authentication
|
|
91
|
+
Query Client
|
|
92
|
+
API Services
|
|
93
|
+
Application Services
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
throughout your routing tree.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
# 3. Route.useRouteContext()
|
|
101
|
+
|
|
102
|
+
Read router context inside a route.
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
const context =
|
|
108
|
+
Route.useRouteContext();
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Access:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
context.auth
|
|
115
|
+
context.queryClient
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Use Cases
|
|
121
|
+
|
|
122
|
+
```txt
|
|
123
|
+
Current User
|
|
124
|
+
Permissions
|
|
125
|
+
Query Client Access
|
|
126
|
+
Application Services
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
# 4. Route.useParams()
|
|
132
|
+
|
|
133
|
+
Read route parameters.
|
|
134
|
+
|
|
135
|
+
Route:
|
|
136
|
+
|
|
137
|
+
```txt
|
|
138
|
+
/users/$id
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
URL:
|
|
142
|
+
|
|
143
|
+
```txt
|
|
144
|
+
/users/123
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Usage:
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
const { id } =
|
|
151
|
+
Route.useParams();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Result:
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
id === "123"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Common Usage
|
|
163
|
+
|
|
164
|
+
```txt
|
|
165
|
+
Detail Pages
|
|
166
|
+
Edit Pages
|
|
167
|
+
Nested Resources
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Examples:
|
|
171
|
+
|
|
172
|
+
```txt
|
|
173
|
+
/patient/123
|
|
174
|
+
/invoice/456
|
|
175
|
+
/user/789
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
# 5. Route.useSearch()
|
|
181
|
+
|
|
182
|
+
Read validated search parameters.
|
|
183
|
+
|
|
184
|
+
URL:
|
|
185
|
+
|
|
186
|
+
```txt
|
|
187
|
+
/users?search=john&type=active
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Validation:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
validateSearch: (search) => ({
|
|
194
|
+
search:
|
|
195
|
+
typeof search.search === "string"
|
|
196
|
+
? search.search
|
|
197
|
+
: "",
|
|
198
|
+
|
|
199
|
+
type:
|
|
200
|
+
typeof search.type === "string"
|
|
201
|
+
? search.type
|
|
202
|
+
: "",
|
|
203
|
+
})
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Usage:
|
|
207
|
+
|
|
208
|
+
```tsx
|
|
209
|
+
const search =
|
|
210
|
+
Route.useSearch();
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Result:
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
{
|
|
217
|
+
search: "john",
|
|
218
|
+
type: "active",
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Why It's Powerful
|
|
225
|
+
|
|
226
|
+
After validation:
|
|
227
|
+
|
|
228
|
+
```tsx
|
|
229
|
+
search.search
|
|
230
|
+
search.type
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
are fully typed.
|
|
234
|
+
|
|
235
|
+
No:
|
|
236
|
+
|
|
237
|
+
```tsx
|
|
238
|
+
searchParams.get()
|
|
239
|
+
Number()
|
|
240
|
+
Boolean()
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
scattered across components.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
# 6. Route.useLoaderData()
|
|
248
|
+
|
|
249
|
+
Reads the value returned by a route loader.
|
|
250
|
+
|
|
251
|
+
Route:
|
|
252
|
+
|
|
253
|
+
```tsx
|
|
254
|
+
loader: async () => {
|
|
255
|
+
return {
|
|
256
|
+
title: "Users",
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Usage:
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
const data =
|
|
265
|
+
Route.useLoaderData();
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Result:
|
|
269
|
+
|
|
270
|
+
```tsx
|
|
271
|
+
data.title
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## Best For
|
|
277
|
+
|
|
278
|
+
```txt
|
|
279
|
+
Page Metadata
|
|
280
|
+
Simple Route Data
|
|
281
|
+
Configuration Data
|
|
282
|
+
Non-Query Information
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Usually Not Needed When Using TanStack Query
|
|
288
|
+
|
|
289
|
+
Preferred pattern:
|
|
290
|
+
|
|
291
|
+
```txt
|
|
292
|
+
Loader
|
|
293
|
+
↓
|
|
294
|
+
ensureQueryData()
|
|
295
|
+
|
|
296
|
+
Component
|
|
297
|
+
↓
|
|
298
|
+
useSuspenseQuery()
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
This leverages:
|
|
302
|
+
|
|
303
|
+
```txt
|
|
304
|
+
Caching
|
|
305
|
+
Invalidation
|
|
306
|
+
Refetching
|
|
307
|
+
Mutations
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
# 7. useRouter()
|
|
313
|
+
|
|
314
|
+
Access the router instance.
|
|
315
|
+
|
|
316
|
+
Example:
|
|
317
|
+
|
|
318
|
+
```tsx
|
|
319
|
+
const router =
|
|
320
|
+
useRouter();
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Common Uses
|
|
326
|
+
|
|
327
|
+
### Navigation
|
|
328
|
+
|
|
329
|
+
```tsx
|
|
330
|
+
router.navigate({
|
|
331
|
+
to: "/users",
|
|
332
|
+
});
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Reload Route Data
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
await router.invalidate();
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Access Router State
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
router.state
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
# 8. router.invalidate()
|
|
350
|
+
|
|
351
|
+
Forces active route loaders to rerun.
|
|
352
|
+
|
|
353
|
+
Example:
|
|
354
|
+
|
|
355
|
+
```tsx
|
|
356
|
+
await router.invalidate();
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
## Useful After
|
|
362
|
+
|
|
363
|
+
```txt
|
|
364
|
+
Login
|
|
365
|
+
Logout
|
|
366
|
+
Location Change
|
|
367
|
+
Role Change
|
|
368
|
+
Permission Updates
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Think:
|
|
372
|
+
|
|
373
|
+
```txt
|
|
374
|
+
QueryClient.invalidateQueries()
|
|
375
|
+
|
|
376
|
+
but for route loaders.
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
# 9. useRouterState()
|
|
382
|
+
|
|
383
|
+
Subscribe to router state updates.
|
|
384
|
+
|
|
385
|
+
Example:
|
|
386
|
+
|
|
387
|
+
```tsx
|
|
388
|
+
const state =
|
|
389
|
+
useRouterState();
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
## Global Loading Indicator
|
|
395
|
+
|
|
396
|
+
```tsx
|
|
397
|
+
const isPending =
|
|
398
|
+
useRouterState({
|
|
399
|
+
select: (state) =>
|
|
400
|
+
state.status === "pending",
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Usage:
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
{
|
|
408
|
+
isPending &&
|
|
409
|
+
<TopLoader />
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Great For
|
|
416
|
+
|
|
417
|
+
```txt
|
|
418
|
+
Progress Bars
|
|
419
|
+
Global Skeletons
|
|
420
|
+
Route Loading Indicators
|
|
421
|
+
Analytics Tracking
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
# 10. loaderDeps()
|
|
427
|
+
|
|
428
|
+
Specify values that should trigger loader re-execution.
|
|
429
|
+
|
|
430
|
+
Example:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
loaderDeps: ({ search }) => ({
|
|
434
|
+
search: search.search,
|
|
435
|
+
page: search.page,
|
|
436
|
+
})
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## Why Use It?
|
|
442
|
+
|
|
443
|
+
Without it:
|
|
444
|
+
|
|
445
|
+
```txt
|
|
446
|
+
Search Changes
|
|
447
|
+
↓
|
|
448
|
+
Loader Might Not Rerun
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
With it:
|
|
452
|
+
|
|
453
|
+
```txt
|
|
454
|
+
Search Changes
|
|
455
|
+
↓
|
|
456
|
+
Loader Reruns
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Best For
|
|
462
|
+
|
|
463
|
+
```txt
|
|
464
|
+
Tables
|
|
465
|
+
Filters
|
|
466
|
+
Pagination
|
|
467
|
+
Search Screens
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
---
|
|
471
|
+
|
|
472
|
+
# 11. Route.useNavigate()
|
|
473
|
+
|
|
474
|
+
Route-scoped navigation helper.
|
|
475
|
+
|
|
476
|
+
Example:
|
|
477
|
+
|
|
478
|
+
```tsx
|
|
479
|
+
const navigate =
|
|
480
|
+
Route.useNavigate();
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Usage:
|
|
484
|
+
|
|
485
|
+
```tsx
|
|
486
|
+
navigate({
|
|
487
|
+
search: {
|
|
488
|
+
page: 2,
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## Best For
|
|
496
|
+
|
|
497
|
+
```txt
|
|
498
|
+
Updating Search Params
|
|
499
|
+
Relative Navigation
|
|
500
|
+
Pagination
|
|
501
|
+
Filtering
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
# 12. useMatchRoute()
|
|
507
|
+
|
|
508
|
+
Determine if a route matches.
|
|
509
|
+
|
|
510
|
+
Example:
|
|
511
|
+
|
|
512
|
+
```tsx
|
|
513
|
+
const matchRoute =
|
|
514
|
+
useMatchRoute();
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Usage:
|
|
518
|
+
|
|
519
|
+
```tsx
|
|
520
|
+
const isUsersPage =
|
|
521
|
+
matchRoute({
|
|
522
|
+
to: "/users",
|
|
523
|
+
});
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## Great For
|
|
529
|
+
|
|
530
|
+
```txt
|
|
531
|
+
Sidebar Active States
|
|
532
|
+
Menu Highlighting
|
|
533
|
+
Conditional UI
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
# 13. Route Preloading
|
|
539
|
+
|
|
540
|
+
Manual route prefetching.
|
|
541
|
+
|
|
542
|
+
Example:
|
|
543
|
+
|
|
544
|
+
```tsx
|
|
545
|
+
router.preloadRoute({
|
|
546
|
+
to: "/reports",
|
|
547
|
+
});
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
or
|
|
551
|
+
|
|
552
|
+
```tsx
|
|
553
|
+
<Link
|
|
554
|
+
to="/reports"
|
|
555
|
+
preload="intent"
|
|
556
|
+
/>
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
---
|
|
560
|
+
|
|
561
|
+
## Benefit
|
|
562
|
+
|
|
563
|
+
```txt
|
|
564
|
+
Hover Link
|
|
565
|
+
↓
|
|
566
|
+
Route Downloads
|
|
567
|
+
↓
|
|
568
|
+
Instant Navigation
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
# 14. pendingComponent
|
|
574
|
+
|
|
575
|
+
Route-level loading UI.
|
|
576
|
+
|
|
577
|
+
Example:
|
|
578
|
+
|
|
579
|
+
```tsx
|
|
580
|
+
export const Route =
|
|
581
|
+
createFileRoute("/users")({
|
|
582
|
+
pendingComponent:
|
|
583
|
+
UsersSkeleton,
|
|
584
|
+
});
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Shown while:
|
|
588
|
+
|
|
589
|
+
```txt
|
|
590
|
+
Loader Running
|
|
591
|
+
Route Loading
|
|
592
|
+
Navigation Pending
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
# 15. pendingMs
|
|
598
|
+
|
|
599
|
+
Delay pendingComponent appearance.
|
|
600
|
+
|
|
601
|
+
Example:
|
|
602
|
+
|
|
603
|
+
```tsx
|
|
604
|
+
pendingMs: 300
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Behavior:
|
|
608
|
+
|
|
609
|
+
```txt
|
|
610
|
+
<300ms
|
|
611
|
+
↓
|
|
612
|
+
No Skeleton
|
|
613
|
+
|
|
614
|
+
>300ms
|
|
615
|
+
↓
|
|
616
|
+
Show Skeleton
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## Prevents
|
|
622
|
+
|
|
623
|
+
```txt
|
|
624
|
+
Loading Flicker
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
for very fast requests.
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
# 16. pendingMinMs
|
|
632
|
+
|
|
633
|
+
Minimum display duration for pendingComponent.
|
|
634
|
+
|
|
635
|
+
Example:
|
|
636
|
+
|
|
637
|
+
```tsx
|
|
638
|
+
pendingMinMs: 500
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
Behavior:
|
|
642
|
+
|
|
643
|
+
```txt
|
|
644
|
+
Skeleton Appears
|
|
645
|
+
↓
|
|
646
|
+
Remains Visible For 500ms
|
|
647
|
+
↓
|
|
648
|
+
Content Displays
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Prevents
|
|
654
|
+
|
|
655
|
+
```txt
|
|
656
|
+
Flashy Loading States
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
# 17. notFoundComponent
|
|
662
|
+
|
|
663
|
+
Route-specific 404 handling.
|
|
664
|
+
|
|
665
|
+
Example:
|
|
666
|
+
|
|
667
|
+
```tsx
|
|
668
|
+
export const Route =
|
|
669
|
+
createFileRoute("/users")({
|
|
670
|
+
notFoundComponent:
|
|
671
|
+
UserNotFound,
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## Great For
|
|
678
|
+
|
|
679
|
+
```txt
|
|
680
|
+
Patient Not Found
|
|
681
|
+
Invoice Not Found
|
|
682
|
+
User Not Found
|
|
683
|
+
Record Not Found
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
# 18. Search Param Validation
|
|
689
|
+
|
|
690
|
+
One of TanStack Router's strongest features.
|
|
691
|
+
|
|
692
|
+
Example:
|
|
693
|
+
|
|
694
|
+
```tsx
|
|
695
|
+
validateSearch: (search) => ({
|
|
696
|
+
page:
|
|
697
|
+
Number(search.page ?? 1),
|
|
698
|
+
|
|
699
|
+
search:
|
|
700
|
+
typeof search.search === "string"
|
|
701
|
+
? search.search
|
|
702
|
+
: "",
|
|
703
|
+
})
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## Benefit
|
|
709
|
+
|
|
710
|
+
After validation:
|
|
711
|
+
|
|
712
|
+
```tsx
|
|
713
|
+
const search =
|
|
714
|
+
Route.useSearch();
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
Result:
|
|
718
|
+
|
|
719
|
+
```tsx
|
|
720
|
+
search.page
|
|
721
|
+
search.search
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
are already typed.
|
|
725
|
+
|
|
726
|
+
---
|
|
727
|
+
|
|
728
|
+
# Recommended Learning Order
|
|
729
|
+
|
|
730
|
+
## Level 1 - Daily Usage
|
|
731
|
+
|
|
732
|
+
```tsx
|
|
733
|
+
<Link />
|
|
734
|
+
<Outlet />
|
|
735
|
+
|
|
736
|
+
Route.useParams()
|
|
737
|
+
|
|
738
|
+
Route.useSearch()
|
|
739
|
+
|
|
740
|
+
useNavigate()
|
|
741
|
+
|
|
742
|
+
redirect()
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
---
|
|
746
|
+
|
|
747
|
+
## Level 2 - Most Useful Features
|
|
748
|
+
|
|
749
|
+
```tsx
|
|
750
|
+
beforeLoad()
|
|
751
|
+
|
|
752
|
+
loader()
|
|
753
|
+
|
|
754
|
+
pendingComponent
|
|
755
|
+
|
|
756
|
+
ensureQueryData()
|
|
757
|
+
|
|
758
|
+
useSuspenseQuery()
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
---
|
|
762
|
+
|
|
763
|
+
## Level 3 - Intermediate
|
|
764
|
+
|
|
765
|
+
```tsx
|
|
766
|
+
createRootRouteWithContext()
|
|
767
|
+
|
|
768
|
+
Route.useRouteContext()
|
|
769
|
+
|
|
770
|
+
useRouter()
|
|
771
|
+
|
|
772
|
+
useRouterState()
|
|
773
|
+
|
|
774
|
+
router.invalidate()
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## Level 4 - Advanced
|
|
780
|
+
|
|
781
|
+
```tsx
|
|
782
|
+
loaderDeps()
|
|
783
|
+
|
|
784
|
+
useMatchRoute()
|
|
785
|
+
|
|
786
|
+
Route Preloading
|
|
787
|
+
|
|
788
|
+
pendingMs
|
|
789
|
+
|
|
790
|
+
pendingMinMs
|
|
791
|
+
|
|
792
|
+
notFoundComponent
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
# Features That Usually Win Over React Router Users
|
|
798
|
+
|
|
799
|
+
```txt
|
|
800
|
+
1. Route.useSearch() + validateSearch()
|
|
801
|
+
|
|
802
|
+
2. beforeLoad()
|
|
803
|
+
|
|
804
|
+
3. createRootRouteWithContext()
|
|
805
|
+
|
|
806
|
+
4. Route.useParams()
|
|
807
|
+
|
|
808
|
+
5. Automatic Route Type Safety
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
These are typically the features that make larger TanStack Router applications feel significantly cleaner and easier to maintain than equivalent React Router implementations.
|