Getting Started
The core of a single-page application is its router. The router is responsible for matching locations to its known routes and for powering navigation within the application.
The Router
A router is created using a history
function and a routes
array.
import { createRouter, prepareRoutes } from '@curi/router';
import { browser } from "@hickory/browser";
let routes = prepareRoutes([...]);
let router = createRouter(browser, routes);
URLs
Locations are represented using URLs. URLs are a combination of a pathname
string, a query
, and a hash
.
The router provides a url
method for automatically generating a URL. The method takes the name of the route and the route's params to generate the URL's pathname
. Additionally, query
and hash
values can be provided.
let routes = prepareRoutes([
{ name: "Home", path: "" },
{ name: "Contact", path: "contact/:method" }
]);
let router = createRouter(browser, routes);
let homeURL = router.url({ name: "Home" });
// "/"
let phoneURL = router.url({
name: "Contact",
params: { method: "phone" }
});
// "/contact/phone"
let queryURL = router.url({
name: "Home",
query: "value=7"
});
// "/?value=7"
By default, a query
is a string, but you can also configure your history to use a query library.
import { parse, stringify } from "qs";
let router = createRouter(browser, routes, {
history: {
query: { parse, stringify }
}
});
let queryURL = router.url({
name: "Home",
query: { value: "6" }
});
// "/?value=6"
Navigation
There are two types of navigation within a single-page application: in-app navigation (e.g. clicking a link) and platform navigation (e.g. clicking the back button or typing a URL in the address bar and hitting enter).
A Curi router object has a navigate
method to let you navigate with code. The function takes an object with a url
property of the URL to navigate to; this pairs well with the router's url
method described above. There are also a number of other optional arguments to navigate
.
router.navigate({
url: "/photo/1357/02468#comments"
});
Response Handlers
When Curi matches a location to a route, it creates a "response" object. Respons objects provide information about the route that matched.
Response handlers are functions that will be called when there is a new response. There are three types of response handlers: side effects, one time functions, and observers.
Side effects are passed to the router when you are creating it. These are best suited for non-rendering tasks. You can read more about them in the side effects guide.
let router = createRouter(browser, routes, {
sideEffects: [scroll(), title(...)]
})
Response handlers registered with router.once
will only be called one time. This is primarily useful for waiting for asynchronous actions to finish before the initial render.
let router = createRouter(browser, routes);
// wait for the initial route's async action to complete
router.once(() => {
// this is not called until the initial response is ready
// so we can safely render in here
});
Observers are passed to the router using router.observe
. Unlike one time functions, these will be called every time there is a new response.
Render packages, like @curi/react-dom
, use router.observe
internally in order to re-render when there is a new response.
router.observe(({ response }) => {
console.log('new response!', response);
});
Rendering
Curi adapts its API to work with different UI libraries. You can check out the respective guides for the officially supported libraries to see how to use them.