Solid.js note: In Solid, useRouteNode() returns reactive state as Accessor<RouteContext>. Call the accessor to read: const routeState = useRouteNode("users"); routeState().route?.name
Angular note: injectRouteNode(name) returns the same RouteSignals shape as injectRoute(). Must be called in injection context. Creates a per-component subscription -- destroyed automatically via DestroyRef.
Basic Example
functionUsersLayout(){const{ route, previousRoute, navigator }=useRouteNode("users");// Component updates only on navigation within users.*return(<div><h1>Users Section</h1>{route ? <Outlet/> : <p>Select a user</p>}</div>);}
3. Parameters
Parameter
Type
Required
Description
nodeName
string
Yes
Route node name to subscribe to
Parameter Details
nodeName
Empty string "": Root node — reacts to all route changes
Node name (e.g., "users"): Reacts only when route starts with this node
Nested node (e.g., "admin.settings"): Reacts to admin.settings and its descendants
Value examples:
nodeName
Reacts to
Doesn't react to
""
All routes
—
"users"
users, users.list, users.view
home, items
"admin.settings"
admin.settings, admin.settings.security
admin, admin.dashboard
4. Return Value
Type: RouteContext
Description: Object with route state and navigator instance
Return Value Structure
Field
Type
Description
navigator
Navigator
Navigator instance for navigation and state access
route
State | undefined
Current route if node is active; undefined if node is inactive
previousRoute
State | undefined
Previous route
route Specifics
Unlike useRoute, the route field will be undefined when the specified node is inactive:
// At route "home"const{ route }=useRouteNode("users");// route === undefined (node "users" is inactive)// At route "users.list"const{ route }=useRouteNode("users");// route === { name: "users.list", ... } (node is active)
5. Dependencies and Context
Required Providers
Provider
Required
Description
RouterProvider
Yes
Must wrap the component using the hook
Used Hooks
useRouter() — getting router instance
useSyncExternalStore — optimized subscription to router state
useMemo — memoization for reference stability
6. Re-render Behavior
Reference stability: Returned RouteContext object is stable between renders if state hasn't changed
Update triggers: Component re-renders only when:
Navigation affects the specified node
Route parameters change within the node
Node becomes active/inactive
reload: true option is used
Memoization: Hook automatically memoizes result
Shared subscription: Internally backed by createRouteNodeSource(router, nodeName) from @real-router/sources, which is cached per (router, nodeName). N components calling useRouteNode("users") against the same router share one router subscription — not N.
When Re-render Does NOT Happen
// With useRouteNode("users"):// - Navigation home → items — NO re-render// - Navigation items → items.detail — NO re-render
When Re-render DOES Happen
// With useRouteNode("users"):// - Navigation home → users.list — re-render (node became active)// - Navigation users.list → users.view — re-render (change within node)// - Navigation users.view → home — re-render (node became inactive)
7. Possible Errors
Condition
Error
How to Avoid
Hook called outside RouterProvider
"useRouter must be used within a RouterProvider"
Wrap component in RouterProvider
8. Behavior
Main Scenarios
Root node ("") receives all route updates
Specific node receives updates only for its branch
route becomes undefined when node is inactive
previousRoute preserves last route before leaving node
Edge Cases
Router not started: route and previousRoute will be undefined
Multiple hooks for same node: All receive same values
Deeply nested nodes: Correctly track activity
reload: true: Triggers update even on same route
Guarantees
Reference stability on re-render without state changes
Correct previousRoute tracking through navigation chain
Independent operation of parallel nodes
9. Related Hooks
Hook
When to Use Instead
useRoute
When you need subscription to all route changes
useRouter
When you only need router instance without subscription
10. Usage Examples
Basic Example — Section Layout
import{useRouteNode}from"@real-router/react";functionUsersLayout(){const{ route, navigator }=useRouteNode("users");if(!route){// Node is inactive — can show placeholder or redirectreturnnull;}return(<divclassName="users-layout"><nav><buttononClick={()=>navigator.navigate("users.list")}>List</button><buttononClick={()=>navigator.navigate("users.create")}>
Create
</button></nav><main>{/* Content based on route.name */}</main></div>);}
Re-render Optimization in Deep Hierarchy
// Each Layout subscribes only to its nodefunctionAdminLayout(){const{ route }=useRouteNode("admin");// Re-renders only on changes in admin.*return<div>{/* ... */}</div>;}functionSettingsLayout(){const{ route }=useRouteNode("admin.settings");// Re-renders only on changes in admin.settings.*return<div>{/* ... */}</div>;}functionSecuritySettings(){const{ route }=useRouteNode("admin.settings.security");// Re-renders only on changes in admin.settings.security.*return<div>{/* ... */}</div>;}
// Don't use useRouteNode for all routesfunctionBad(){const{ route }=useRouteNode("");// Equivalent to useRoutereturn<div>{route?.name}</div>;}// Use useRoute for global subscriptionfunctionGood(){const{ route }=useRoute();return<div>{route?.name}</div>;}
// Don't check activity manuallyfunctionBad(){const{ route }=useRoute();constisUsersActive=route?.name?.startsWith("users");// Component re-renders on ANY navigation}// Use useRouteNode for optimizationfunctionGood(){const{ route }=useRouteNode("users");// route will be undefined if node is inactive// Component does NOT re-render on navigation outside users}
// Don't create redundant subscriptionsfunctionBad(){const{route: route1}=useRouteNode("users");const{route: route2}=useRouteNode("users");// Duplication!}// Use one hook and pass data via props/contextfunctionGood(){const{ route }=useRouteNode("users");return<ChildComponentroute={route}/>;}
11. Migration from router5
Comparison of @real-router/react/useRouteNode with react-router5/useRouteNode from router5.
Version Comparison
router5 (react-router5)
Real Router (@real-router/react)
Export
export default function useRouteNode()
export function useRouteNode()
Signature
useRouteNode(nodeName: string): RouteContext
useRouteNode(nodeName: string): RouteContext
route type
State (always defined)
State | undefined
previousRoute type
State | null
State | undefined
Subscription
useState + useEffect
useSyncExternalStore
Return field router
{ router: Router, ... }
Replaced by navigator: Navigator
1. Breaking Changes
Severity
What Changed
Was
Now
Impact
CRITICAL
Export type
export default
export function (named)
All imports will break
HIGH
Context validation
Returns undefined router if no provider
Throws Error
Code without provider will crash
HIGH
route behavior on inactive node
Always State (last route)
undefined when node is inactive
Activity check logic will change
MEDIUM
previousRoute type
State | null
State | undefined
Need to replace null checks
LOW
External dependency
router5-transition-path
Built-in router.shouldUpdateNode()
No impact on user
HIGH
Return field router
router: Router in return value
navigator: Navigator
Update destructuring and method calls
Parameter Changes
Parameter nodeName unchanged.
Return Value Changes
Field
Change
Migration
route
On inactive node returns undefined instead of last route
Use route directly to check node activity
previousRoute
Type State | null → State | undefined
Replace !== null with truthiness check
router
Field removed — replaced by navigator: Navigator
Use navigator instead; it provides navigate, getState, subscribe
Examples
// Code that will break (import)importuseRouteNodefrom"react-router5";// Code after migrationimport{useRouteNode}from"@real-router/react";
// Code that will break (activity check)const{ route }=useRouteNode("users");constisActive=route.name.startsWith("users");// route was always defined// Code after migrationconst{ route }=useRouteNode("users");constisActive=!!route;// route === undefined when node is inactive// orif(route){// node is active}
// Code that will break (previousRoute)if(previousRoute!==null){/* ... */}// Code after migrationif(previousRoute){/* ... */}
2. Implementation Changes
Subscription Mechanism
Was: useState + useEffect with manual subscription via router.subscribe()
Now: useSyncExternalStore — modern React API for external stores
Advantages of New Approach
Concurrent Mode compatibility: useSyncExternalStore works correctly with Suspense and concurrent rendering
No tearing: Guarantees UI consistency even with fast updates
Fewer bugs: Removed potential race conditions from manual subscription
New Behavior on Inactive Node
Was: route contained last route regardless of node activity
Now: route becomes undefined when node is inactive
This change simplifies component logic:
// New approach — simplerif(route){// node is active, show content}
Optimizations
Selector caching: shouldUpdate function cached per router and node name
Stable references: Result memoized via useMemo
Fail-fast validation: Clear error when provider is missing
3. Dependency Changes
Dependency
Was
Now
Router package
router5
@real-router/core
React bindings
react-router5
@real-router/react
External utility
router5-transition-path.shouldUpdateNode
Built-in shouldUpdateNode() from router
4. Migration Guide
Checklist
Replace import useRouteNode from 'react-router5' with import { useRouteNode } from '@real-router/react'
Change activity check: use if (route) instead of checking route.name
Replace !== null checks with truthiness check for previousRoute
Ensure component is wrapped in RouterProvider
Remove extra activity checks — route === undefined means inactive node
Step-by-Step Migration
Update imports: Replace default import with named import
Simplify activity checks: Instead of route.name.startsWith(node) use !!route
Update null checks: Replace with undefined or truthiness checks
Check providers: Ensure RouterProvider exists
Test edge cases: Check behavior on node entry/exit
5. Summary
Category
Status
Breaking Changes
CRITICAL (export, route behavior)
New parameters
None
Removed parameters
None
Behavior changes
route=undefined on inactive node
Optimizations
useSyncExternalStore, caching, memoization
Maximum severity: CRITICAL — import changes and activity check logic changes required