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 asynchronous methods.

Route interactions are defined using objects with four properties: name, register, get, and reset.

{
  // The string you will use to call the interaction.
  name: 'my',

  // A function used internally to register routes
  // with the interaction. You only need to use this when
  // writing your own interactions.
  register: function(route, parentData) {...},

  // This is the function that you will call. For example,
  // with this interaction, the get function will be
  // called when you call router.route.my('...')
  get: function(route) {...},
  reset: function() {...}
}

Instead of importing the actual route interaction object, you typically import a factory function to create the object. This isn't absolutely necessary, but is useful for server-side rendering.

// interactions/my.js
export default function createMyInteraction() {
  return {
    name: "my",
    register() {...},
    get() {...},
    reset() {...}
  };
}

// index.js
import createMyInteraction from "./interactions/my";

const interaction = createMyInteraction();

Adding Interactions

Route interactions are provided to the router call as an array using the route property of the options object (the third argument).

const router = curi(history, routes, {
  route: [createMyInteraction()]
});

The route interaction will be added to the router's route property. When you call an interaction, you pass the name of the route that you want to interact with.

const myValue = router.route.my('Some Route', ...);

Creating Route Interactions

There are a few steps to creating your own route interactions.

Remember to export a function that will create the interaction object, not the actual interaction object.

// we'll create an interaction that confirms
// a route is registered
export default function confirmInteraction() {
  ...
}

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

propertydescription
namea unique identifier for the route interaction
registera function to internally store information about routes
geta function that will receive a route's name (and possibly other arguments) and perform some task using the related route
reseta function that will reset the interaction's internal state (this is used if you call router.replaceRoutes())
export default function confirmInteraction() {
  // maintain an object of known routes
  let knownRoutes = {};
  return {
    name: 'confirm',
    // when a route is registered,
    // we store it using its name
    register: route => {
      knownRoutes[route.name] = true;
    },
    // get checks the known routes to see if one exists
    // with the requested name
    get: (name) => {
      return knownRoutes[name] != null
    },
    // reset the known routes
    reset: () => {
      knownRoutes = {};
    }
  };
}

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 confirmFactory from './interactions/confirm'

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

const router = curi(history, routes, {
  route: [confirmFactory()]
});

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

Slightly more advanced

You might want to write an interaction that uses data from parent routes when registering a route. For example, the built-in pathname interaction joins a route's path with it parent path(s).

The second argument passed to a router interaction's register() function is a parent data object. For root routes, this will be undefined. For nested routes, this is the value returned by the parent route's register() function.

function ParentFactory() {
  let 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];
    },
    reset: () => {
      routeTree = {};
    }
  }
}