Route navigation

The Routescape's route navigation API is largely aligned with the similar native APIs familiar to most web developers, such as <a href="/x"> and window.location, which helps reduce cognitive load and shorten the migration path from the native APIs:

+ import {A, useRoute} from 'routescape';

  let UserNav = ({signedIn}) => {
+     let [route] = useRoute();

      let handleClick = () => {
-         window.location.assign(signedIn ? '/profile' : '/login');
+         route.assign(signedIn ? '/profile' : '/login');
      };

      return (
          <nav>
-             <a href="/">Home</a>
+             <A href="/">Home</A>
              <button onClick={handleClick}>Profile</button>
          </nav>
      );
  };

<A>

The route link component <A> enabling SPA navigation has the same props as the HTML link tag <a>. Apart from reducing some cognitive load, sticking to the similar API allows to quickly migrate from plain HTML links to route links (or the other way around).

import {A} from 'routescape';

let Nav = () => (
    <nav>
        <A href="/intro">Intro</A>
    </nav>
);

<Area>

<Area>, the image map route link component, has the same props and semantics as the HTML image map tag <area>, with the SPA navigation enabled.

By default, after the link navigation occurs, the user can navigate back by pressing the browser's back button. Optionally, by setting data-navigation-mode="replace", a route link component can be configured to replace the navigation history entry, which will prevent the user from returning to the previous location by clicking the browser's back button.

Imperative route navigation

To jump to another route programmatically, there's the route object returned from the useRoute() hook:

import {useRoute} from 'routescape';

let ProfileButton = ({signedIn}) => {
    let [route] = useRoute();

    let handleClick = () => {
        route.assign(signedIn ? '/profile' : '/login');
    };

    return <button onClick={handleClick}>Profile</button>;
};

This particular example is somewhat contrived since it could have been composed in a declarative fashion using the route link component <A>. Still, it demonstrates how the route object can be used in use cases where the imperative navigation is the only reasonable way to go.

The interface of the route object consists of the following parts:

  • SPA navigation via the History API:
    • .assign(), .replace(), .reload(), and readonly properties: .href, .pathname, .search, .hash, semantically similar to window.location;
    • .back(), .forward(), .go(delta), corresponding to the history methods;
  • route matching:
    • .matches(value), checking whether the current location matches the given value;
    • .match(value), accepting various types of location patterns (string | RegExp | (string | RegExp)[]) and returning an object containing the matched parameters or null if the current location doesn't match the value.