router-query/repository-context/docs/router/guide/router-events.md
Version 663282b0ebbc.bb1 · MIT. This preview displays packaged text and does not execute code. Treat the contents as untrusted instructions.
← Return to resource and package checksum
title: Router Events
TanStack Router exposes router lifecycle events through router.subscribe. This is useful for imperative side effects like analytics, resetting external state, or running DOM-dependent logic after navigation.
Basic usage
router.subscribe takes an event name and a listener, then returns an unsubscribe function:
const unsubscribe = router.subscribe('onResolved', (event) => {
console.info('Navigation finished:', event.toLocation.href)
})
// Later, clean up the listener
unsubscribe()
When to use it
router.subscribe is best for imperative integrations that need to observe navigation without driving rendering:
- Analytics and pageview tracking
- Resetting external caches or mutation state
- Logging navigation timing and transitions
- Running DOM-dependent logic after routes render
If you need reactive UI updates, prefer framework hooks like useRouterState, useSearch, and useParams instead of subscribing manually.
Available events
TanStack Router emits these lifecycle events:
onBeforeNavigate- right before a navigation beginsonBeforeLoad- before route loading startsonLoad- after the next location has committed and route matches have loadedonBeforeRouteMount- after loading finishes, just before route components mountonResolved- after the navigation has fully resolvedonRendered- after the route has rendered
For the full event payload types, see the RouterEvents type.
Typical event flow
For a normal navigation, the events usually flow like this:
onBeforeNavigateonBeforeLoadonLoadonBeforeRouteMountonResolvedonRendered
You usually do not need every event. A good rule of thumb is:
- Use
onBeforeNavigateoronBeforeLoadto observe navigation start - Use
onResolvedfor analytics and cleanup after navigation finishes - Use
onRenderedfor DOM-dependent work
Event payload
Navigation events receive location change metadata describing what changed:
const unsubscribe = router.subscribe('onBeforeNavigate', (event) => {
console.info({
from: event.fromLocation?.href,
to: event.toLocation.href,
pathChanged: event.pathChanged,
hrefChanged: event.hrefChanged,
hashChanged: event.hashChanged,
})
})
A few useful details:
fromLocationcan beundefinedon the initial loadpathChangedtells you whether the pathname changedhrefChangedincludes pathname, search, and hash changeshashChangedis useful for distinguishing hash-only navigations
Common patterns
Track pageviews
onResolved is a good default for analytics because it fires after navigation finishes:
const unsubscribe = router.subscribe('onResolved', ({ toLocation }) => {
analytics.track('page_view', {
path: toLocation.pathname,
href: toLocation.href,
})
})
Clear external mutation state
If you use a mutation library without keyed mutation state, clear it after navigation:
const unsubscribe = router.subscribe('onResolved', ({ pathChanged }) => {
if (pathChanged) {
mutationCache.clear()
}
})
Run DOM-dependent logic
Use onRendered when your side effect depends on the new route content already being in the DOM:
const unsubscribe = router.subscribe('onRendered', ({ toLocation }) => {
focusPageHeading(toLocation.pathname)
})
Unsubscribing in components
If you subscribe from a component or framework effect, always return the unsubscribe function from your cleanup so the listener is removed when the component unmounts.