0
# React Hooks
1
2
React hooks for accessing router state, navigation functions, route data, parameters, and managing router interactions. These hooks provide type-safe access to all router functionality.
3
4
## Capabilities
5
6
### Router Access Hooks
7
8
Hooks for accessing the router instance and router state.
9
10
```typescript { .api }
11
/**
12
* Access the router instance
13
* @param opts - Options for router access
14
* @returns Router instance
15
*/
16
function useRouter<TRouter extends AnyRouter = RegisteredRouter>(
17
opts?: { warn?: boolean }
18
): TRouter;
19
20
/**
21
* Subscribe to router state changes
22
* @param opts - Router state subscription options
23
* @returns Selected router state
24
*/
25
function useRouterState<
26
TRouter extends AnyRouter = RegisteredRouter,
27
TSelected = RouterState<TRouter>,
28
TStructuralSharing extends boolean = true
29
>(
30
opts?: {
31
router?: TRouter;
32
select?: (state: RouterState<TRouter>) => TSelected;
33
structuralSharing?: TStructuralSharing;
34
}
35
): UseRouterStateResult<TRouter, TSelected>;
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { useRouter, useRouterState } from "@tanstack/react-router";
42
43
function MyComponent() {
44
// Access router instance
45
const router = useRouter();
46
47
// Subscribe to loading state
48
const isLoading = useRouterState({
49
select: (state) => state.isLoading,
50
});
51
52
// Subscribe to current location
53
const location = useRouterState({
54
select: (state) => state.location,
55
});
56
57
return (
58
<div>
59
Current path: {location.pathname}
60
{isLoading && <div>Loading...</div>}
61
</div>
62
);
63
}
64
```
65
66
### Navigation Hooks
67
68
Hooks for programmatic navigation and location access.
69
70
```typescript { .api }
71
/**
72
* Get navigation function for programmatic navigation
73
* @param defaultOpts - Default navigation options
74
* @returns Type-safe navigation function
75
*/
76
function useNavigate<
77
TRouter extends AnyRouter = RegisteredRouter,
78
TDefaultFrom extends RoutePaths<TRouter> = "/"
79
>(
80
defaultOpts?: { from?: TDefaultFrom }
81
): UseNavigateResult<TRouter, TDefaultFrom>;
82
83
/**
84
* Access current location with optional selection
85
* @param opts - Location access options
86
* @returns Current location or selected subset
87
*/
88
function useLocation<
89
TRouter extends AnyRouter = RegisteredRouter,
90
TSelected = ParsedLocation,
91
TStructuralSharing extends boolean = true
92
>(
93
opts?: {
94
select?: (location: ParsedLocation) => TSelected;
95
structuralSharing?: TStructuralSharing;
96
}
97
): UseLocationResult<TSelected>;
98
99
/**
100
* Check if browser can navigate back
101
* @returns Whether back navigation is possible
102
*/
103
function useCanGoBack(): boolean;
104
```
105
106
**Usage Examples:**
107
108
```typescript
109
import { useNavigate, useLocation, useCanGoBack } from "@tanstack/react-router";
110
111
function NavigationComponent() {
112
const navigate = useNavigate();
113
const location = useLocation();
114
const canGoBack = useCanGoBack();
115
116
// Navigate programmatically
117
const handleNavigate = () => {
118
navigate({
119
to: "/posts/$postId",
120
params: { postId: "123" },
121
search: { tab: "comments" },
122
});
123
};
124
125
// Navigate with state
126
const handleNavigateWithState = () => {
127
navigate({
128
to: "/profile",
129
state: { fromDashboard: true },
130
replace: true,
131
});
132
};
133
134
return (
135
<div>
136
<p>Current path: {location.pathname}</p>
137
<button onClick={handleNavigate}>Go to Post</button>
138
<button onClick={() => navigate({ to: -1 })} disabled={!canGoBack}>
139
Go Back
140
</button>
141
</div>
142
);
143
}
144
```
145
146
### Route Data Hooks
147
148
Hooks for accessing route-specific data, parameters, and search values.
149
150
```typescript { .api }
151
/**
152
* Access route parameters with type safety
153
* @param opts - Params access options
154
* @returns Route parameters or selected subset
155
*/
156
function useParams<
157
TRouter extends AnyRouter = RegisteredRouter,
158
TFrom extends RoutePaths<TRouter> = "/",
159
TStrict extends boolean = true,
160
TThrow extends boolean = true,
161
TSelected = ResolveParams<TRouter, TFrom>,
162
TStructuralSharing extends boolean = true
163
>(
164
opts?: {
165
from?: TFrom;
166
strict?: TStrict;
167
shouldThrow?: TThrow;
168
select?: (params: ResolveParams<TRouter, TFrom>) => TSelected;
169
structuralSharing?: TStructuralSharing;
170
}
171
): UseParamsResult<TRouter, TFrom, TStrict, TThrow, TSelected>;
172
173
/**
174
* Access search parameters with type safety
175
* @param opts - Search access options
176
* @returns Search parameters or selected subset
177
*/
178
function useSearch<
179
TRouter extends AnyRouter = RegisteredRouter,
180
TFrom extends RoutePaths<TRouter> = "/",
181
TStrict extends boolean = true,
182
TThrow extends boolean = true,
183
TSelected = InferFullSearchSchema<TRouter, TFrom>,
184
TStructuralSharing extends boolean = true
185
>(
186
opts?: {
187
from?: TFrom;
188
strict?: TStrict;
189
shouldThrow?: TThrow;
190
select?: (search: InferFullSearchSchema<TRouter, TFrom>) => TSelected;
191
structuralSharing?: TStructuralSharing;
192
}
193
): UseSearchResult<TRouter, TFrom, TStrict, TThrow, TSelected>;
194
195
/**
196
* Access loader data from route
197
* @param opts - Loader data access options
198
* @returns Loader data or selected subset
199
*/
200
function useLoaderData<
201
TRouter extends AnyRouter = RegisteredRouter,
202
TFrom extends RoutePaths<TRouter> = "/",
203
TStrict extends boolean = true,
204
TSelected = ResolveLoaderData<TRouter, TFrom>,
205
TStructuralSharing extends boolean = true
206
>(
207
opts?: {
208
from?: TFrom;
209
strict?: TStrict;
210
select?: (data: ResolveLoaderData<TRouter, TFrom>) => TSelected;
211
structuralSharing?: TStructuralSharing;
212
}
213
): UseLoaderDataResult<TRouter, TFrom, TStrict, TSelected>;
214
215
/**
216
* Access loader dependencies
217
* @param opts - Loader deps access options
218
* @returns Loader dependencies
219
*/
220
function useLoaderDeps<
221
TRouter extends AnyRouter = RegisteredRouter,
222
TFrom extends RoutePaths<TRouter> = "/",
223
TStrict extends boolean = true,
224
TSelected = ResolveLoaderDeps<TRouter, TFrom>,
225
TStructuralSharing extends boolean = true
226
>(
227
opts?: {
228
from?: TFrom;
229
strict?: TStrict;
230
select?: (deps: ResolveLoaderDeps<TRouter, TFrom>) => TSelected;
231
structuralSharing?: TStructuralSharing;
232
}
233
): UseLoaderDepsResult<TRouter, TFrom, TStrict, TSelected>;
234
235
/**
236
* Access route context
237
* @param opts - Route context access options
238
* @returns Route context or selected subset
239
*/
240
function useRouteContext<
241
TRouter extends AnyRouter = RegisteredRouter,
242
TFrom extends RoutePaths<TRouter> = "/",
243
TStrict extends boolean = true,
244
TSelected = RouteContext<TRouter, TFrom>,
245
TStructuralSharing extends boolean = true
246
>(
247
opts?: {
248
from?: TFrom;
249
strict?: TStrict;
250
select?: (context: RouteContext<TRouter, TFrom>) => TSelected;
251
structuralSharing?: TStructuralSharing;
252
}
253
): UseRouteContextResult<TRouter, TFrom, TStrict, TSelected>;
254
```
255
256
**Usage Examples:**
257
258
```typescript
259
import { useParams, useSearch, useLoaderData, useRouteContext } from "@tanstack/react-router";
260
261
function PostDetail() {
262
// Access route parameters
263
const { postId } = useParams({ from: "/posts/$postId" });
264
265
// Access search parameters with selection
266
const page = useSearch({
267
from: "/posts/$postId",
268
select: (search) => search.page || 1,
269
});
270
271
// Access loader data
272
const { post, comments } = useLoaderData({ from: "/posts/$postId" });
273
274
// Access route context
275
const user = useRouteContext({
276
select: (context) => context.user,
277
});
278
279
return (
280
<div>
281
<h1>{post.title}</h1>
282
<p>Post ID: {postId}</p>
283
<p>Page: {page}</p>
284
<p>Viewing as: {user.name}</p>
285
</div>
286
);
287
}
288
```
289
290
### Route Match Hooks
291
292
Hooks for accessing route matches and match-related functionality.
293
294
```typescript { .api }
295
/**
296
* Access route match data
297
* @param opts - Match access options
298
* @returns Route match or selected subset
299
*/
300
function useMatch<
301
TRouter extends AnyRouter = RegisteredRouter,
302
TFrom extends RoutePaths<TRouter> = "/",
303
TStrict extends boolean = true,
304
TThrow extends boolean = true,
305
TSelected = RouteMatch<TRouter, TFrom>,
306
TStructuralSharing extends boolean = true
307
>(
308
opts?: {
309
from?: TFrom;
310
strict?: TStrict;
311
shouldThrow?: TThrow;
312
select?: (match: RouteMatch<TRouter, TFrom>) => TSelected;
313
structuralSharing?: TStructuralSharing;
314
}
315
): UseMatchResult<TRouter, TFrom, TStrict, TThrow, TSelected>;
316
317
/**
318
* Access all active route matches
319
* @param opts - Matches access options
320
* @returns Array of route matches or selected subset
321
*/
322
function useMatches<
323
TRouter extends AnyRouter = RegisteredRouter,
324
TSelected = RouteMatch[],
325
TStructuralSharing extends boolean = true
326
>(
327
opts?: {
328
select?: (matches: RouteMatch[]) => TSelected;
329
structuralSharing?: TStructuralSharing;
330
}
331
): UseMatchesResult<TSelected>;
332
333
/**
334
* Access parent matches relative to current match
335
* @param opts - Parent matches access options
336
* @returns Array of parent matches or selected subset
337
*/
338
function useParentMatches<
339
TRouter extends AnyRouter = RegisteredRouter,
340
TSelected = RouteMatch[],
341
TStructuralSharing extends boolean = true
342
>(
343
opts?: {
344
select?: (matches: RouteMatch[]) => TSelected;
345
structuralSharing?: TStructuralSharing;
346
}
347
): UseMatchesResult<TSelected>;
348
349
/**
350
* Access child matches relative to current match
351
* @param opts - Child matches access options
352
* @returns Array of child matches or selected subset
353
*/
354
function useChildMatches<
355
TRouter extends AnyRouter = RegisteredRouter,
356
TSelected = RouteMatch[],
357
TStructuralSharing extends boolean = true
358
>(
359
opts?: {
360
select?: (matches: RouteMatch[]) => TSelected;
361
structuralSharing?: TStructuralSharing;
362
}
363
): UseMatchesResult<TSelected>;
364
365
/**
366
* Get function to check if routes match current location
367
* @returns Function that returns match params or false
368
*/
369
function useMatchRoute<TRouter extends AnyRouter = RegisteredRouter>(): (
370
opts: UseMatchRouteOptions<TRouter>
371
) => false | AllParams<TRouter>;
372
```
373
374
**Usage Examples:**
375
376
```typescript
377
import { useMatch, useMatches, useParentMatches, useMatchRoute } from "@tanstack/react-router";
378
379
function RouteInfo() {
380
// Access current match
381
const match = useMatch();
382
383
// Access all matches with breadcrumb info
384
const breadcrumbs = useMatches({
385
select: (matches) => matches.map(match => ({
386
id: match.id,
387
pathname: match.pathname,
388
title: match.context?.title || match.routeId,
389
})),
390
});
391
392
// Access parent matches
393
const parentMatches = useParentMatches();
394
395
// Check route matching
396
const matchRoute = useMatchRoute();
397
const isOnProfile = matchRoute({ to: "/profile" });
398
399
return (
400
<div>
401
<nav>
402
{breadcrumbs.map((crumb) => (
403
<span key={crumb.id}>{crumb.title} / </span>
404
))}
405
</nav>
406
<p>Current match: {match.routeId}</p>
407
<p>Parent matches: {parentMatches.length}</p>
408
{isOnProfile && <p>Currently on profile page</p>}
409
</div>
410
);
411
}
412
```
413
414
### Navigation Blocking Hooks
415
416
Hooks for blocking navigation based on conditions.
417
418
```typescript { .api }
419
/**
420
* Block navigation conditionally
421
* @param opts - Navigation blocking options
422
* @returns Blocker resolver if using resolver pattern
423
*/
424
function useBlocker<
425
TRouter extends AnyRouter = RegisteredRouter,
426
TWithResolver extends boolean = false
427
>(
428
opts: {
429
shouldBlockFn: ShouldBlockFn;
430
enableBeforeUnload?: boolean | (() => boolean);
431
disabled?: boolean;
432
withResolver?: TWithResolver;
433
}
434
): TWithResolver extends true ? BlockerResolver : void;
435
436
type ShouldBlockFn = (
437
fromLocation: ParsedLocation,
438
toLocation: ParsedLocation
439
) => boolean;
440
441
interface BlockerResolver {
442
status: "idle" | "blocked";
443
confirm: () => void;
444
cancel: () => void;
445
}
446
```
447
448
**Usage Examples:**
449
450
```typescript
451
import { useBlocker } from "@tanstack/react-router";
452
453
function FormWithUnsavedChanges() {
454
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
455
456
// Block navigation if there are unsaved changes
457
useBlocker({
458
shouldBlockFn: () => hasUnsavedChanges,
459
enableBeforeUnload: true,
460
});
461
462
// With resolver pattern
463
const blocker = useBlocker({
464
shouldBlockFn: () => hasUnsavedChanges,
465
withResolver: true,
466
});
467
468
return (
469
<form>
470
<input onChange={() => setHasUnsavedChanges(true)} />
471
472
{blocker.status === "blocked" && (
473
<div>
474
<p>You have unsaved changes. Are you sure you want to leave?</p>
475
<button onClick={blocker.confirm}>Yes, leave</button>
476
<button onClick={blocker.cancel}>Stay</button>
477
</div>
478
)}
479
</form>
480
);
481
}
482
```
483
484
### Async Data Hooks
485
486
Hooks for handling deferred promises and async data.
487
488
```typescript { .api }
489
/**
490
* Handle deferred promises with suspense
491
* @param options - Await options
492
* @returns Tuple of resolved data and promise state
493
*/
494
function useAwaited<T>(
495
options: AwaitOptions<T>
496
): [T, DeferredPromise<T>];
497
498
interface AwaitOptions<T> {
499
/** Promise to await */
500
promise: Promise<T>;
501
}
502
503
interface DeferredPromise<T> extends Promise<T> {
504
__deferredState: DeferredPromiseState<T>;
505
}
506
507
interface DeferredPromiseState<T> {
508
status: "pending" | "success" | "error";
509
data?: T;
510
error?: any;
511
}
512
```
513
514
**Usage Examples:**
515
516
```typescript
517
import { useAwaited, defer } from "@tanstack/react-router";
518
519
function AsyncDataComponent() {
520
const { deferredPosts } = useLoaderData();
521
522
try {
523
const [posts, promise] = useAwaited({ promise: deferredPosts });
524
525
return (
526
<div>
527
<h2>Posts (Status: {promise.__deferredState.status})</h2>
528
{posts.map(post => (
529
<div key={post.id}>{post.title}</div>
530
))}
531
</div>
532
);
533
} catch (promise) {
534
// This will suspend until the promise resolves
535
throw promise;
536
}
537
}
538
```
539
540
### Link Props Hook
541
542
Hook for getting link element props with all link logic applied.
543
544
```typescript { .api }
545
/**
546
* Get props for link elements with all link logic
547
* @param options - Link options
548
* @param forwardedRef - Optional forwarded ref
549
* @returns Props object for anchor element
550
*/
551
function useLinkProps<
552
TRouter extends AnyRouter = RegisteredRouter,
553
TFrom extends string = string,
554
TTo extends string | undefined = undefined,
555
TMaskFrom extends string = TFrom,
556
TMaskTo extends string = ""
557
>(
558
options: UseLinkPropsOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>,
559
forwardedRef?: React.ForwardedRef<Element>
560
): React.ComponentPropsWithRef<"a">;
561
562
interface UseLinkPropsOptions<TRouter extends AnyRouter, TFrom extends string, TTo extends string | undefined, TMaskFrom extends string, TMaskTo extends string>
563
extends LinkOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> {
564
/** Disabled state */
565
disabled?: boolean;
566
}
567
```
568
569
**Usage Examples:**
570
571
```typescript
572
import { useLinkProps } from "@tanstack/react-router";
573
574
function CustomLink({ to, children, ...props }) {
575
const linkProps = useLinkProps({
576
to,
577
activeProps: { className: "active" },
578
preload: "intent",
579
...props,
580
});
581
582
return (
583
<a {...linkProps} className={`custom-link ${linkProps.className || ""}`}>
584
{children}
585
</a>
586
);
587
}
588
```
589
590
### Utility Hooks
591
592
Utility hooks for common React patterns and DOM interactions.
593
594
```typescript { .api }
595
/**
596
* Hook for accessing previous values across renders
597
* @param value - Current value
598
* @returns Previous value or null if no previous value
599
*/
600
function usePrevious<T>(value: T): T | null;
601
602
/**
603
* Hook for stable callback references that don't cause re-renders
604
* @param fn - Function to stabilize
605
* @returns Stable function reference
606
*/
607
function useStableCallback<T extends (...args: Array<any>) => any>(fn: T): T;
608
609
/**
610
* Hook for working with forwarded refs
611
* @param ref - Forwarded ref from React.forwardRef
612
* @returns Inner ref that can be used on DOM elements
613
*/
614
function useForwardedRef<T>(ref?: React.ForwardedRef<T>): React.RefObject<T>;
615
616
/**
617
* Hook for IntersectionObserver functionality
618
* @param ref - Ref to element to observe
619
* @param callback - Callback when intersection changes
620
* @param intersectionObserverOptions - IntersectionObserver options
621
* @param options - Hook-specific options
622
*/
623
function useIntersectionObserver<T extends Element>(
624
ref: React.RefObject<T | null>,
625
callback: (entry: IntersectionObserverEntry | undefined) => void,
626
intersectionObserverOptions?: IntersectionObserverInit,
627
options?: { disabled?: boolean }
628
): void;
629
630
/**
631
* Hook for custom element scroll restoration
632
* @param options - Scroll restoration configuration
633
* @returns Scroll restoration entry if available
634
*/
635
function useElementScrollRestoration(
636
options: (
637
| {
638
id: string;
639
getElement?: () => Window | Element | undefined | null;
640
}
641
| {
642
id?: string;
643
getElement: () => Window | Element | undefined | null;
644
}
645
) & {
646
getKey?: (location: ParsedLocation) => string;
647
}
648
): ScrollRestorationEntry | undefined;
649
```
650
651
**Usage Examples:**
652
653
```typescript
654
import {
655
usePrevious,
656
useStableCallback,
657
useForwardedRef,
658
useIntersectionObserver,
659
useElementScrollRestoration,
660
} from "@tanstack/react-router";
661
662
// Previous value tracking
663
function CounterComponent({ count }: { count: number }) {
664
const prevCount = usePrevious(count);
665
666
return (
667
<div>
668
Current: {count}, Previous: {prevCount}
669
</div>
670
);
671
}
672
673
// Stable callbacks to prevent re-renders
674
function ExpensiveComponent({ onUpdate }: { onUpdate: (data: any) => void }) {
675
const stableOnUpdate = useStableCallback(onUpdate);
676
677
// This won't cause child re-renders when onUpdate reference changes
678
return <ChildComponent onUpdate={stableOnUpdate} />;
679
}
680
681
// Forwarded refs
682
const CustomInput = React.forwardRef<HTMLInputElement>((props, ref) => {
683
const innerRef = useForwardedRef(ref);
684
685
return <input ref={innerRef} {...props} />;
686
});
687
688
// Intersection observer
689
function LazyImage({ src, alt }: { src: string; alt: string }) {
690
const [isVisible, setIsVisible] = useState(false);
691
const imgRef = useRef<HTMLImageElement>(null);
692
693
useIntersectionObserver(
694
imgRef,
695
(entry) => {
696
if (entry?.isIntersecting) {
697
setIsVisible(true);
698
}
699
},
700
{ rootMargin: "100px" }
701
);
702
703
return (
704
<img
705
ref={imgRef}
706
src={isVisible ? src : undefined}
707
alt={alt}
708
/>
709
);
710
}
711
712
// Element scroll restoration
713
function CustomScrollableComponent() {
714
const containerRef = useRef<HTMLDivElement>(null);
715
716
const scrollEntry = useElementScrollRestoration({
717
id: "custom-scrollable",
718
getElement: () => containerRef.current,
719
});
720
721
useEffect(() => {
722
if (scrollEntry && containerRef.current) {
723
containerRef.current.scrollTop = scrollEntry.scrollY;
724
}
725
}, [scrollEntry]);
726
727
return <div ref={containerRef}>...</div>;
728
}
729
```
730
731
## Types
732
733
### Hook Result Types
734
735
```typescript { .api }
736
type UseNavigateResult<TRouter extends AnyRouter, TDefaultFrom extends RoutePaths<TRouter>> =
737
<TTo extends RoutePaths<TRouter> = "/", TFrom extends RoutePaths<TRouter> = TDefaultFrom>(
738
options: NavigateOptions<TRouter, TFrom, TTo>
739
) => Promise<void>;
740
741
type UseLocationResult<TSelected> = TSelected extends ParsedLocation
742
? ParsedLocation
743
: TSelected;
744
745
type UseParamsResult<TRouter extends AnyRouter, TFrom extends RoutePaths<TRouter>, TStrict extends boolean, TThrow extends boolean, TSelected> =
746
TStrict extends false
747
? TThrow extends false
748
? TSelected | undefined
749
: TSelected
750
: TSelected;
751
752
type UseSearchResult<TRouter extends AnyRouter, TFrom extends RoutePaths<TRouter>, TStrict extends boolean, TThrow extends boolean, TSelected> =
753
TStrict extends false
754
? TThrow extends false
755
? TSelected | undefined
756
: TSelected
757
: TSelected;
758
759
type UseMatchesResult<TSelected> = TSelected;
760
```
761
762
### Hook Options Types
763
764
```typescript { .api }
765
interface UseMatchRouteOptions<TRouter extends AnyRouter = AnyRouter> {
766
to: RoutePaths<TRouter>;
767
params?: Record<string, any>;
768
search?: Record<string, any>;
769
hash?: string;
770
fuzzy?: boolean;
771
includeSearch?: boolean;
772
includeHash?: boolean;
773
}
774
```