History

A router's history enables navigation. It is responsible for creating the location objects, interfacing with its native environment (e.g. a browser) to perform navigation, and telling the router that navigation has occured.

Curi uses Hickory packages for its history implementations. Hickory is designed with asynchronous navigation in mind. This means that when a user clicks a link, your application can load data for the matched route before updating the location.

import { browser } from "@hickory/browser";
let router = createRouter(browser, routes);

You most likely will not need to interact directly with the application's history, but you should be familiar with the different choices.

Types of History

There are three Hickory packages to choose from. Which one you use depends on where your application is running.

Browser History

import { browser } from "@hickory/browser";
let router = createRouter(browser, routes);

The browser history is used for applications running in a browser.

If you use the browser history, your application should be hosted on a server that can handle dynamic requests. This either means:

  1. A server with real time route matching (like an Express server).
  2. Configuring the server to respond with a fallback page when the request doesn't map to a real file on the server (e.g. with NGINX or Apache).
  3. Using a static file host that can be configured to respond with a fallback page.

Hash History

import { hash } from "@hickory/hash";
let router = createRouter(Hash, routes);

The hash history is a fallback history for applications running in a browser. It should only be used if you cannot configure the server to respond to requests that don't match files on the server. The browser history is almost always a better choice.

In Memory History

import { inMemory, createReusable } from "@hickory/in-memory";

let router = createRouter(inMemory, routes);
// or
let reusable = createReusable();
let router = createRouter(reusable, routes);

An in-memory history is used for applications not running in a browser. For example, the in memory history is used on the server, in a React Native app, and during testing. The @hickory/in-memory package provides two in-memory history types.

The inMemory function is a full history object, capable of in-app navigation, which is useful for native applications and testing.

The createReusable function returns lightweight history function for server-side rendering. The returned history cannot navigate, which is fine for server rendering.

Locations

The history object will map URL strings into location objects. Only the pathname, query (search), and hash components of a URL are used; locations ignore a URL's domain and protocol.

Matching locations to routes only uses the location's pathname.

// https://www.example.com/page?key=value#trending
location = {
  pathname: "/page",
  query: "key=value"
  hash: "trending"
}

Query Objects

The query value of a location is a string by default, but the history object can be configured to automatically parse it into an object.

You can choose whichever query parsing/stringifying package you prefer. Some of the most popular are qs, query-string, and querystring.

import { parse, stringify } from "qs";
import { browser } from "@hickory/browser";

let router = createRouter(browser, routes, {
  history: {
    query: { parse, stringify }
  }
});

// https://www.example.com/page?key=value#trending
location = {
  pathname: "/page",
  query: { key: "value" }
  hash: "trending"
}

A history object has two methods for navigation: navigate and go.

go

The go method allows you to jump to another, already visited. go takes one argument, the number of locations forward (positive numbers) or backward (negative numbers) to go.

history.go(-1); // go back to the previous location

In browsers, there is "external" navigation. This includes the user typing a URL in the address bar and clicking the browser's forward and back buttons. These navigations are all treated similarly to the go method.

There are three types of navigation with navigate: push, replace, and anchor.

Push navigation adds a new location after the current location. Any locations that existed after the current location are wiped out by push navigation.

Replace navigation replaces the current location with a new location. This has no effect on any locations after the current location.

Anchor navigation is a mix between push and replace. If the new location is the same as the current location, it replaces; otherwise, it pushes. This behavior is the same as how clicking an <a> in a multi-page application works, hence the name "anchor".

For more details on the history objects and their APIs, please check out the Hickory documentation.