Navigating
Navigator lets a component navigate from code:
import { Navigator } from "./routes";
export class Toolbar extends Component {
route = this.use(Navigator);
// A method, not an inline arrow: a handler built during render is re-attached to
// the element on every render, and development builds report it (RMD020).
showPlayer() {
this.route.push("/players/9");
}
render() {
return (
<nav>
<button onclick={this.route.back}>← Back</button>
<button onclick={this.showPlayer}>Player 9</button>
</nav>
);
}
}
push(href, opts?) | go to a URL, adding a history entry |
replace(href, opts?) | go there without adding one |
updateSearchParams(next, opts?) | change only the query — see keeping state in the URL |
updateHashTags(next, opts?) | change only the hash |
back() / forward() | move through history |
Scrolling is your choice, per call
A push or replace moves to another page, so it scrolls to the top by default.
Pass { scroll: false } to stay where you are — useful when a <RouteOutlet> sits
partway down a long page and you don't want the jump. The in-place updaters
(updateSearchParams, updateHashTags) are the opposite: they don't scroll unless
you ask with { scroll: true }.
The methods are already bound
onclick={this.route.back} works as-is — the hook's methods are bound to it, so
passing one as a handler keeps working. No () => this.route.back() wrapper needed.
push or <Link>?
Use <Link> when the thing is a link — someone should be able to
middle-click it and a crawler should follow it. Use push when the navigation is the
result of something else: a submitted form, a resolved choice, a redirect after a
save.
The Router hook can do this too
The component that mounts the router with this.use(Router) doesn't need a separate
Navigator to read the URL or navigate — the Router instance exposes the same
pathname, searchParams, hashTags, push, replace, updateSearchParams,
updateHashTags, back and forward, on top of the setup work it does. It's the same
surface, from the piece that owns the state:
@Host("div")
export class App extends Component {
router = this.use(Router);
goHome() {
this.router.push("/");
}
render() {
return (
<div className="app">
<button onclick={this.goHome}>{this.router.pathname}</button>
<RouteOutlet routes={routes} />
</div>
);
}
}
The one thing it can't give you is params() — those are matched by a <RouteOutlet>,
which sits below the Router, so only a Navigator inside a routed page has them.
There is no global router
You can't import the router and call push from just anywhere — navigation is
reachable only from inside the tree, through Navigator. (A module-level router would
be shared by every request on a server, so one visitor's navigation could show up for
another.) If a plain function needs to navigate, pass it a callback — the component
calling it has the hook.
Next
- Nested outlets — routes inside routes.