Routing
Routing in your components is possible via @webcomp/router
module.
WebComp router is a modern client side router that provides Express-like route handling, supports history API and hash mode and provides some higher order helpers. Let's go through everything.
Basic usage
Here's how you can define routes in your component:
import { WebComponent } from '@webcomp/core';
import { Router } from '@webcomp/router';
class MyElement extends WebComponent{
componentDidMount = () => {
Router.on('/profile/:id', this.handleRouteChange);
}
handleRouteChange = (url) => {
console.log('Route changed! ID:', url.params.id); // "Route changed! ID: 123"
}
changeRoute = () => {
Router.push('/profile/123');
}
render() {
return <button onClick={this.changeRoute}>Change Route</button>
}
}
Your route handler function will receive a url
object with the following structure:
params
- object with url paramspath
- Full path stringquery
- Parsed object from query string
Router Methods and Properties
Besides push
and on
that we've already seen, router provides a few additional methods and configuration options.
Router.mode
Router.mode
Default:
hash
A string indicating router's operation mode. Can be hash
or history
. To configure router for a different mode, assign a new value to it:
Router.mode = 'history';
Keep in mind that this will configure the entire router, so you should only do it once at the top level of your app (before you register any of your components).
Router.root
Router.root
Default:
/
A string indicating router's root path. Same as with mode, you can assign a new value to set it:
Router.root = '/settings';
This should also be configured once at the top level of your app.
`on(route, handlerFunction, persist)`
`on(route, handlerFunction, persist)`
Define a new handler for a route. Optional persist
argument will prevent a handler from flushing if Router.flushHandlers
is called.
Calling Router.on
will return a string ID which you can use to remove handlers later if needed. Usage:
Router.on('/profile/:id', (url) => {
console.log(url.params.id);
})
removeHandler(id)
removeHandler(id)
Removes previously defined route handler by it's ID. Usage:
Router.removeHandler('_mp6vmcfda');
flushHandlers()
flushHandlers()
Removes all handlers from the router except ones that were defined with persist
flag.
dangerouslyFlushRouter()
dangerouslyFlushRouter()
Completely resets router to it's default state. Root is set to '/'
, mode to 'hash'
and all route handlers are removed (even persisted ones).
You will most likely never need to use this method. If you must, use with caution.
push(path)
Navigate to a new route. Uses `pushState` when in `history` mode. Usage:
Router.push('/path/to/something');
replace(path)
replace(path)
Navigate to a new route and replace the history state instead of pushing.
Note: Only available in history
mode.
Routerize
decorator
Routerize
decoratorDefining routes explicitly isn't always convenient. Some times you just want to watch what happens and do stuff based on that. For these use cases, WebComp provides a @routerize
decorator:
import { WebComponent } from '@webcomp/core';
import { routerize } from '@webcomp/router';
@routerize
class MyElement extends WebComponent{
render(props) {
// props.router.state is the same object that is passed to route handlers
return <h1>Hello route {props.router.state.path}</h1>
}
}
Here's the structure of this.props.router
prop that @routerize
gives you:
{
on(),
push()
replace(),
flushHandlers(),
dangerouslyFlushRouter(),
root,
state: {
path,
params: {},
query: {},
},
}
This will be updated on every route change, so you can rely on the prop directly, without needing to specify route handlers.
Note: Due to how router works by default, your component will be re-rendered on mount when routerized. It's usually not a big deal, but if it is, you should use a custom router (see below) with a skipInitial
option.
<Route /> Component
If you only need to watch routes to change your rendered content, you can use <Route />
component to do that:
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';
class MyElement extends WebComponent{
render(props) {
return (
<div>
<Route path="/">
<h1>Home Page</h1>
</Route>
<Route path="/settings">
<h1>Settings</h1>
</Route>
</div>
)
}
}
Shallow routes
Besides child node, Route
also supports passing a `component` prop for render. If you do this, rendered component will automatically be routerized. You can bypass this behavior by using shallow
prop.
import { WebComponent } from '@webcomp/core';
import { Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';
class MyElement extends WebComponent{
render(props) {
return (
<div>
<Route path="/" component={FancyHeader} />
<Route path="/settings" component={FancyHeader} shallow />
</div>
)
}
}
In the above example, FancyHeader
component on route /
will get this.props.router
, but the one on /settings
route won't.
Advanced Usage
Custom Routers
In some cases you need to have different router configurations for different components. WebComp allows you to create custom routers for this.
Default Router
is an instance of a WCRouter
class, which you can reuse or extend.
import { WCRouter } from '@webcomp/router';
class SafeRouter extends WCRouter {
constructor(options) {
super(options);
this.dangerouslyFlushRouter = () => throw new Error("Safe router doesn't allow flushing");
this.flushHandlers = () => throw new Error("Safe router doesn't allow flushing");
}
}
const MyCustomRouter = new SafeRouter({ skipInitial: true, mode: 'history' });
Custom router options
skipInitial
- If this is set, router won't fire handlers on initial page load.mode
- Set default mode. Can be'hash'
or'history'
.root
- Set custom default root
Routerizing with custom router
The @routerize
decorator uses default router instance. If you want to routerize your component with your custom router, you can use routerizeWith
decorator instead:
import { WebComponent } from '@webcomp/core';
import { WCRouter, routerizeWith } from '@webcomp/router';
const CustomRouter = new WCRouter({ skipInitial: true });
@routerizeWith(CustomRouter)
class MyElement extends WebComponent{
render(props) {
return <h1>...</h1>
}
}
Using custom routers with <Route />
<Route />
You can also use custom routers with <Route />
component by providing it as a customRouter
prop:
import { WebComponent } from '@webcomp/core';
import { WCRouter, Route } from '@webcomp/router';
import FancyHeader from './FancyHeader';
const MyRouter = new WCRouter({ skipInitial: true });
class MyElement extends WebComponent{
render(props) {
return (
<div>
<Route path="/" component={FancyHeader} customRouter={MyRouter} />
</div>
)
}
}
Last updated
Was this helpful?