Route Interactions

Route interactions let you interact with a registered route using its name.

A registered route is generally any route that is in the array of routes that you used to create your router. However, some interactions only register routes that meet some criteria. For example, the prefetch interaction only registers routes with a resolve property.

Calling Intearctions

Every interaction has a unique name. The interaction can be called as a property of a route's route object. The first argument to the call is always the name of the route to interact with. Some interactions may also take additional arguments.

router.route.myInteraction("Home");
router.route.otherInteraction("User", false);

Built-in Interactions

Curi comes with two built-in interactions: pathname and active.

The pathname interaction is used to generate a pathname string for a route. This is done using the route's name and an object of route params (if they are necessary).

router.route.pathname("User", { id: 1 });

The active interaction determines if a route is active by comparing it to a response object.

router.route.active("Home", response);

Adding Interactions

Route interactions are attached to routes using the second argument to prepareRoutes, which is an array of route interactions.

The router will make the interactions that it receives from its routes available through its route property.

const routes = prepareRoutes(
  routes,
  [createMyInteraction()] // name = myInteraction
);
const router = createRouter(browser, routes);
router.route // all interactions

Creating Route Interactions

Curi provides some interactions for common use cases, but you may have need to create a custom interaction. There are a few steps to creating your own route interactions.

While not strictly require, interactions are commonly created from a function so that multiple instances of the interaction can be safely created.

For this example, we'll create an interaction that confirms that a route is registered.

function confirmInteraction() {
  ...
}

The function should return an object with three properties: name, register, and get.

name

A unique identifier for the route interaction.

register

A function to internally store data about routes. The stored data will be accessible from the interaction's get method.

The first argument to register is the "public" data for a route, such as its name and route param keys. Data should be stored using the route's name.

The second argument, which is optional, is data from the route's parent. If a register method returns a value, the returned value will be passed as the second value when registering the route's children routes.

get

A function that will receive a route's name (and possibly other arguments) and perform some task using the related route. If the interaction's register method stored data about the route, it can be read here.

With these properties, we can create our confirmation interaction.

function confirmInteraction() {
  // maintain a set of known routes
  const knownRoutes = new Set();
  return {
    name: 'confirm',
    // when a route is registered,
    // we store it using its name
    register: route => {
      knownRoutes.add(route.name);
    },
    // get checks the known routes to see if one exists
    // with the requested name
    get: (name) => {
      return knownRoutes.has(name);
    }
  };
}

In your application, you can import it, call the factory to create the interaction, and register the interaction when you create the router.

import { curi, prepareRoutes } from '@curi/router';
import createConfirmation from './interactions/confirm'

const routes = prepareRoutes(
  [{ name: 'Home', path: '' }],
  [createConfirmation()]
);

const router = createRouter(browser, routes);

router.route.confirm('Home'); // true
router.route.confirm('Elsewhere'); // false

Slightly more advanced

For a more advanced example, we can take advantage of the second argument to register.

For root routes (no parent route), the second argument will be undefined. For nested routes, this is the value returned by the parent route's register function.

function parentInteraction() {
  const routeTree = {};
  return {
    name: 'routeParent',
    register: (route, parent) => {
      routeTree[route.name] = parent;
      // we return route.name and any child routes will
      // receive that as their parent value
      return route.name;
    },
    get: (name) => {
      return routeTree[name];
    }
  }
}

Curi handles passing the return value of register to the route's children automatically.