Async Routes

Async Routes with resolve and reject

A route can have async({ app, router, to, from, direction, resolve, reject }) instead of component. The router waits: resolve(content, options) loads the page and reject() cancels. fetchBook(id) in src/js/api.js is a fake API that waits 600 ms, then returns a copy of the book or throws:

The async book route and a redirect function in src/js/routes.jsJavaScript
  { path: '/books/top/', redirect: ({ resolve }) => resolve(`/books/${topRated().id}/`) },
  {
    path: '/books/:id(\\d+)/',
    name: 'book',
    options: { props: { source: 'route' } },
    async({ app, to, resolve, reject }) {
      app.preloader.show();
      fetchBook(to.params.id)
        .then((book) => resolve({ component: BookPage }, { props: { book } }))
        .catch((err) => {
          reject();
          app.toast.show({ text: err.message, closeTimeout: 2000 });
        })
        .finally(() => app.preloader.hide());
    },
A preloader over the catalog while book 2 loads, and the toast after rejecting /books/99/
A preloader over the catalog while book 2 loads, and the toast after rejecting /books/99/

A bad id never reaches the page. Navigating to /books/99/, then tapping Staff pick (Passing Data Between Pages):

Output of 30
--- navigate /books/99/
   610 ms  api   GET /books/99 -> 404 in 603 ms
router.url is /
--- tap Staff pick
   671 ms  api   GET /books/5 -> 200 in 612 ms
   672 ms  book props: id, source, badge, book

The router stayed on /. Props merged four sources: the :id parameter, the route's options.props, the navigation props and those of resolve(), so book.f7 now starts with const book = props.book ||, keeping its Store lookup as the fallback. Top rated redirected to Salt and Saffron (4.8). Each tap now waits about 700 ms.