# Using npm
npm install observable-tree-router
# Using yarn
yarn add observable-tree-routerThis library has a peer dependency on RxJS v7.0.0 or higher:
npm install rxjs@^7.0.0observable-tree-router is a TypeScript-friendly, reactive router designed for single page applications. It provides a hierarchical, state-oriented approach to routing with full type safety, making it ideal for complex applications that require a predictable and typesafe routing solution.
Unlike traditional imperative routers, observable-tree-router treats routing as an observable state tree. This enables reactive patterns and makes it easy to synchronize your UI with the current route state.
- Observable state - Full reactive approach with RxJS observables
- Hierarchical routing - Nested routes with inherited parameters
- Type-safe params - Utilize TypeScript's type system to ensure route parameters are correct
- Cascading params - Nested routes have access to parent route parameters
First, define your routes and create a router:
import { createBrowserRouter, route } from 'observable-tree-router';
import { createBrowserHistory } from 'history';
// Create a browser history instance
const history = createBrowserHistory();
// Define your routes
const router = createBrowserRouter(history, {
home: route({ path: '/' }),
about: route({ path: '/about' }),
users: route({ path: '/users' })
});Routes can have parameters that are extracted from the URL:
const router = createBrowserRouter(history, {
user: route({
path: '/user/:userId',
params: ['userId']
})
});
// Navigate to a user profile with a specific ID
router.user.push({ userId: '123' });Routes can be nested to create hierarchical structures:
const router = createBrowserRouter(history, {
user: route({
path: '/user/:userId',
params: ['userId'],
nested: {
profile: route({ path: '/profile' }),
posts: route({ path: '/posts' })
}
})
});
// Navigate to user's profile with ID 123
router.user.profile.push({ userId: '123' });
// URL will be /user/123/profileTo navigate to a route:
// Navigate to home route
router.home.push();
// Navigate to user route with parameters
router.user.push({ userId: '123' });
// Replace current history entry instead of pushing a new one
router.about.replace();Check if a route is currently active:
// Check if route is exactly matching the current URL
if (router.user.isMatchingExact) {
// Current URL matches exactly the user route
}
// Check if route or any nested route is matching
if (router.user.isMatching) {
// Current URL matches the user route or one of its children
}
// Check if a child route is matching
if (router.user.isMatchingChild) {
// A child route of user is matching
}The router state is available as both an observable and a current value:
// Get current router state
const currentState = router.currentState;
// Subscribe to router state changes
router.state$.subscribe(state => {
console.log('Router state changed:', state);
});
// Subscribe to a specific route's state changes
router.user.state$.subscribe(state => {
console.log('User route state changed:', state);
});
// Subscribe to route match changes
router.user.match$.subscribe(match => {
if (match) {
console.log('User route matched with params:', match.params);
console.log('Exact match:', match.exact);
} else {
console.log('User route not matched');
}
});Creates a router that synchronizes with the browser's URL.
history: A history object from the history packageconfig: Router configuration object
Creates a router that doesn't synchronize with the browser's URL, currently unsupported.
config: Router configuration object
Function to create a route configuration.
Options:
path: The URL path pattern (e.g.,/users/:id)params: Array of parameter names that this route extracts from the URLnested: Object containing nested routes
Examples:
// Simple route
route({ path: '/about' })
// Route with parameters
route({ path: '/user/:userId', params: ['userId'] })
// Route with nested routes
route({
path: '/user/:userId',
params: ['userId'],
nested: {
profile: route({ path: '/profile' }),
settings: route({ path: '/settings' })
}
})Each route in the router provides:
push(params?): Navigate to this route with optional parametersreplace(params?): Replace current history entry with this routepath: The full path pattern of this routeisMatching: Whether this route or any of its children match the current URLisMatchingExact: Whether this route exactly matches the current URLisMatchingChild: Whether a child of this route matches the current URLstate$: Observable of this route's statecurrentState: Current state of this routematch$: Observable that emits when route match state changes (entering or leaving route)
The root router provides:
state$: Observable of the entire router statecurrentState: Current state of the entire router
MIT © Mikael Couzic