TanStack Router provides a comprehensive set of hooks for accessing router state, navigation, and route information with full type safety.
Router Hooks
useRouter
Access the current TanStack Router instance from React context.
import { useRouter } from '@tanstack/react-router'
function MyComponent () {
const router = useRouter ()
return < div > Current path: { router . state . location . pathname } </ div >
}
Source: packages/react-router/src/useRouter.tsx:16-25
Log a warning if no router context is found.
The registered router instance.
useRouterState
Subscribe to the router’s state store with optional selection and structural sharing.
import { useRouterState } from '@tanstack/react-router'
function MyComponent () {
const isLoading = useRouterState ({
select : ( state ) => state . isLoading
})
return isLoading ? < Spinner /> : < Content />
}
Source: packages/react-router/src/useRouterState.tsx:44-86
select
(state: RouterState) => TSelected
Project the full router state to a derived slice for render optimization.
Enable structural sharing for stable references (replace-equal semantics).
Read state from a specific router instance instead of context.
The selected router state (or the full state by default).
Navigation Hooks
useNavigate
Imperative navigation hook that returns a stable navigate function.
import { useNavigate } from '@tanstack/react-router'
function MyComponent () {
const navigate = useNavigate ()
const handleClick = () => {
navigate ({ to: '/posts/$postId' , params: { postId: '123' } })
}
return < button onClick = { handleClick } > Go to Post </ button >
}
Source: packages/react-router/src/useNavigate.tsx:26-43
Optional route base used to resolve relative to paths.
returns
(options: NavigateOptions) => Promise<void>
A function that accepts NavigateOptions including:
to - Destination path
params - Path parameters
search - Search parameters
hash - URL hash
replace - Replace history entry
resetScroll - Reset scroll position
useLocation
Read the current location from the router state.
import { useLocation } from '@tanstack/react-router'
function MyComponent () {
const location = useLocation ()
return < div > Current path: { location . pathname } </ div >
}
Source: packages/react-router/src/useLocation.tsx:40-52
select
(location: Location) => TSelected
Project the location object to a derived value.
Enable structural sharing for stable references.
The current location object with properties:
pathname - Current path
search - Parsed search params
hash - URL hash
href - Full URL
state - Location state
Route Data Hooks
useParams
Access the current route’s path parameters with type safety.
import { useParams } from '@tanstack/react-router'
function PostComponent () {
const { postId } = useParams ({ from: '/posts/$postId' })
return < div > Post ID: { postId } </ div >
}
Source: packages/react-router/src/useParams.tsx:76-107
The route ID to get params from.
Whether to enforce strict typing.
select
(params: TParams) => TSelected
Project the params object to a derived value.
Enable structural sharing for stable references.
The params object (or selected value) for the matched route.
useSearch
Read and select the current route’s search parameters with type safety.
import { useSearch } from '@tanstack/react-router'
function PostsComponent () {
const search = useSearch ({ from: '/posts' })
return < div > Page: { search . page } </ div >
}
Source: packages/react-router/src/useSearch.tsx:76-105
The route ID to get search params from.
Control how strictly search is typed.
select
(search: TSearch) => TSelected
Map the search object to a derived value.
Enable structural sharing for stable references.
The search object (or selected value) for the matched route.
useLoaderData
Read and select the current route’s loader data with type safety.
import { useLoaderData } from '@tanstack/react-router'
function PostComponent () {
const { post } = useLoaderData ({ from: '/posts/$postId' })
return < h1 > { post . title } </ h1 >
}
Source: packages/react-router/src/useLoaderData.tsx:68-91
opts
UseLoaderDataOptions
required
The route ID to get loader data from.
Choose strictness of typing.
select
(data: TLoaderData) => TSelected
Map the loader data to a derived value.
Enable structural sharing for stable references.
The loader data (or selected value) for the matched route.
Match Hooks
useMatch
Read and select the nearest or targeted route match.
import { useMatch } from '@tanstack/react-router'
function MyComponent () {
const match = useMatch ({ from: '/posts/$postId' })
return < div > Match ID: { match . id } </ div >
}
Source: packages/react-router/src/useMatch.tsx:82-123
Whether to enforce strict typing.
select
(match: RouteMatch) => TSelected
Project the match to a derived value.
Enable structural sharing.
The route match object containing:
id - Match ID
routeId - Route ID
pathname - Matched pathname
params - Path parameters
search - Search parameters
loaderData - Loader data
context - Route context
useMatches
Read the full array of active route matches or select a derived subset.
import { useMatches } from '@tanstack/react-router'
function Breadcrumbs () {
const matches = useMatches ()
return (
< nav >
{ matches . map ( match => (
< span key = { match . id } > { match . routeId } </ span >
)) }
</ nav >
)
}
Source: packages/react-router/src/Matches.tsx:233-250
select
(matches: RouteMatch[]) => TSelected
Project the matches array to a derived value.
Enable structural sharing.
The array of matches (or the selected value).
useMatchRoute
Create a matcher function for testing locations against route definitions.
import { useMatchRoute } from '@tanstack/react-router'
function MyComponent () {
const matchRoute = useMatchRoute ()
const isPostsPage = matchRoute ({ to: '/posts' })
return isPostsPage ? < PostsHeader /> : < DefaultHeader />
}
Source: packages/react-router/src/Matches.tsx:144-174
returns
(options: MatchRouteOptions) => false | TParams
A matchRoute function that returns false (no match) or the matched params object. Options include:
to - Route to match
params - Match specific params
search - Match specific search
fuzzy - Allow fuzzy matching
pending - Match against pending location
caseSensitive - Case-sensitive matching
Blocker Hook
useBlocker
Block navigation with custom logic and optional user confirmation.
import { useBlocker } from '@tanstack/react-router'
function FormComponent () {
const [ isDirty , setIsDirty ] = useState ( false )
useBlocker ({
shouldBlockFn : () => isDirty ,
enableBeforeUnload: true ,
withResolver: true ,
})
return < form > ... </ form >
}
Source: packages/react-router/src/useBlocker.tsx:131-260
shouldBlockFn
(args: BlockerArgs) => boolean | Promise<boolean>
required
Function to determine if navigation should be blocked. Receives current and next locations.
enableBeforeUnload
boolean | (() => boolean)
default: "true"
Enable browser’s beforeunload warning.
Return a resolver object with proceed/reset functions.
When withResolver: true, returns:
status - ‘idle’ | ‘blocked’
current - Current location info
next - Next location info
action - History action
proceed() - Allow navigation
reset() - Cancel navigation
Usage Examples
Router State Selection
function NavigationIndicator () {
const { isLoading , location } = useRouterState ({
select : ( state ) => ({
isLoading: state . isLoading ,
location: state . location . pathname ,
}),
})
return isLoading ? < ProgressBar /> : null
}
Imperative Navigation
function LoginButton () {
const navigate = useNavigate ()
const handleLogin = async () => {
await loginUser ()
navigate ({
to: '/dashboard' ,
replace: true ,
})
}
return < button onClick = { handleLogin } > Login </ button >
}
Type-Safe Params
function PostPage () {
const { postId , commentId } = useParams ({
from: '/posts/$postId/comments/$commentId' ,
select : ( params ) => ({
postId: params . postId ,
commentId: params . commentId ,
}),
})
return < Comment postId = { postId } commentId = { commentId } />
}
Search Params with Selection
function ProductList () {
const page = useSearch ({
from: '/products' ,
select : ( search ) => search . page ?? 1 ,
})
const products = useProducts ( page )
return < ProductGrid products = { products } />
}
Loader Data Access
function UserProfile () {
const user = useLoaderData ({
from: '/users/$userId' ,
select : ( data ) => data . user ,
})
return (
< div >
< h1 > { user . name } </ h1 >
< p > { user . email } </ p >
</ div >
)
}
Conditional Rendering with Match
function Navigation () {
const matchRoute = useMatchRoute ()
const isSettings = matchRoute ({ to: '/settings' , fuzzy: true })
const isAdmin = matchRoute ({ to: '/admin' })
return (
< nav >
< Link to = "/" > Home </ Link >
{ isSettings && < SettingsNav /> }
{ isAdmin && < AdminNav /> }
</ nav >
)
}
Breadcrumbs with Matches
function Breadcrumbs () {
const matches = useMatches ({
select : ( matches ) => matches . map ( match => ({
id: match . id ,
pathname: match . pathname ,
// Access custom metadata from route
title: match . context ?. breadcrumb ,
})),
})
return (
< nav >
{ matches . map (( match , i ) => (
< span key = { match . id } >
{ i > 0 && ' > ' }
< Link to = { match . pathname } > { match . title } </ Link >
</ span >
)) }
</ nav >
)
}
Navigation Blocker
function EditForm () {
const [ formData , setFormData ] = useState ( initialData )
const [ originalData ] = useState ( initialData )
const hasChanges = ! deepEqual ( formData , originalData )
const blocker = useBlocker ({
shouldBlockFn : ({ current , next }) => {
return hasChanges && current . routeId !== next . routeId
},
withResolver: true ,
})
return (
<>
< form >
< input
value = { formData . title }
onChange = { ( e ) => setFormData ({ ... formData , title: e . target . value }) }
/>
</ form >
{ blocker . status === 'blocked' && (
< Dialog >
< p > You have unsaved changes. Are you sure you want to leave? </ p >
< button onClick = { blocker . proceed } > Leave </ button >
< button onClick = { blocker . reset } > Stay </ button >
</ Dialog >
) }
</>
)
}
Location Tracking
function Analytics () {
const pathname = useLocation ({
select : ( loc ) => loc . pathname
})
useEffect (() => {
trackPageView ( pathname )
}, [ pathname ])
return null
}
Use Selectors
Always use the select option to narrow down your subscription:
// ❌ Re-renders on any router state change
const state = useRouterState ()
// ✅ Only re-renders when isLoading changes
const isLoading = useRouterState ({
select : ( s ) => s . isLoading
})
Enable Structural Sharing
For complex selections, enable structural sharing:
const metadata = useMatches ({
select : ( matches ) => matches . map ( m => m . context ?. metadata ),
structuralSharing: true , // Prevents unnecessary re-renders
})
Memoize Selectors
For expensive selections, memoize the selector:
const selector = useCallback (
( state ) => computeExpensiveValue ( state ),
[ dependencies ]
)
const value = useRouterState ({ select: selector })
See Also