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:
{ 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 bad id never reaches the page. Navigating to /books/99/, then tapping Staff pick (Passing Data Between Pages):
--- 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.