Browse recipes

Observe and control a route transition

Follow one navigation from the active profile to its completed destination.

Table of contents

APIs used

mount
Starts a Valyrian.js application on a DOM target.
onCreate
Runs when a component first enters the rendered tree and may return cleanup or a promise.
afterRoute
Observes completed route changes.
beforeRoute
Observes attempts to leave the current route.
mountRouter
Uses a Router as the mounted navigation root.
redirect
Starts navigation to the supplied URL and optionally avoids pushing browser history.
Router
Coordinates route definitions and resolves navigation through the public router flow.

Run this recipe

Starting project
Use the local TSX and ESM project from Stage 1 with Valyrian.js installed and its ESM browser build configured.
File
Replace src/client-entry.tsx with this recipe snippet.
Run
Run npm run build, serve public with npx --yes serve@14.2.5 public --listen 8000, open http://localhost:8000 and use the example's visible controls.
Observable result
beforeRoute reports the departure attempt, the destination completes, and afterRoute reports Route changed. Initial entry does not run afterRoute.

Starting point

Start on Home with a Router mounted on body.

Steps

Use redirect(url) to open Profile. Its onCreate callback registers beforeRoute for the attempt to leave and afterRoute for the completed destination. Choose Leave profile.

tsx
import { mount, onCreate } from "valyrian.js";
import {
  afterRoute,
  beforeRoute,
  mountRouter,
  redirect,
  Router,
} from "valyrian.js/router";

const status = { message: "Open the profile route." };

const Home = () => (
  <main>
    <p>{status.message}</p>
    <button onclick={() => redirect("/profile")}>Open profile</button>
  </main>
);

const Profile = () => {
  onCreate(() => {
    beforeRoute(() => {
      status.message = "Leaving profile";
      return true;
    });

    afterRoute(() => {
      status.message = "Route changed";
    });
  });

  return (
    <main>
      <p>Profile</p>
      <button onclick={() => redirect("/")}>Leave profile</button>
    </main>
  );
};

const router = new Router();
router.add("/", Home);
router.add("/profile", Profile);
router.catch((_request: { path: string }, error?: unknown) => (
  <main>
    Navigation failed:{" "}
    {error instanceof Error ? error.message : "Unknown error"}
  </main>
));

mountRouter("body", router);

Result

beforeRoute reports the departure attempt, the destination completes, and afterRoute reports Route changed. Initial entry does not run afterRoute.

Limits

Both hooks require an active mounted component context and throw RouterError outside it.

Continue