Vue Router 4–Async Scrolling, Lazy-Loading, and Navigation Errors
Tags: webdev, programming, javascript, vue
Published: 2021-01-25 23:31:00

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


**Vue Router 4 is in beta and it’s subject to change.**

To build a single page app easily, we got to add routing so that URLs will be mapped to components that are rendered.

In this article, we’ll look at how to use Vue Router 4 with Vue 3.

### Async Scrolling Behavior

We can change the scrolling behavior to be async.

To do that, we can write:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vue-router@4.0.0-beta.7/dist/vue-router.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <p>
        <router-link to="/foo">foo</router-link>
        <router-link to="/bar">bar</router-link>
      </p>
      <router-view></router-view>
    </div>
    <script>
      const Foo = {
        template: `<div>
          <p v-for='n in 100'>{{n}}</p>
        </div>`
      };
      const Bar = {
        template: `<div>
          <p v-for='n in 100'>{{n}}</p>
        </div>`
      };
      const routes = [
        {
          path: "/foo",
          component: Foo
        },
        {
          path: "/bar",
          component: Bar
        }
      ];
      const router = VueRouter.createRouter({
        history: VueRouter.createWebHistory(),
        routes,
        scrollBehavior(to, from, savedPosition) {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve({ left: 0, top: 500 });
            }, 500);
          });
        }
      });
      const app = Vue.createApp({});
      app.use(router);
      app.mount("#app");
    </script>
  </body>
</html>
```

We have the `scrollBehavior` method that returns a promise that resolves to an object with the scroll position.

The `left` and `top` properties are the new properties for the x and y coordinates.

They replace the `x` and `y` properties in Vue Router 3.

### Lazy Loading Routes

We can lazy load routes in our app.

For example, we can write:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="[https://unpkg.com/vue@next](https://unpkg.com/vue@next)"></script>
    <script src="[https://unpkg.com/vue-router@4.0.0-beta.7/dist/vue-router.global.js](https://unpkg.com/vue-router@4.0.0-beta.7/dist/vue-router.global.js)"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <p>
        <router-link to="/foo">foo</router-link>
        <router-link to="/bar">bar</router-link>
      </p>
      <router-view></router-view>
    </div>
    <script>
      const Foo = () =>
        Promise.resolve({
          template: `<div>foo</div>`
        });

      const Bar = () =>
        Promise.resolve({
          template: `<div>bar</div>`
        });

      const routes = [
        {
          path: "/foo",
          component: Foo
        },
        {
          path: "/bar",
          component: Bar
        }
      ];
      const router = VueRouter.createRouter({
        history: VueRouter.createWebHistory(),
        routes
      });
      const app = Vue.createApp({});
      app.use(router);
      app.mount("#app");
    </script>
  </body>
</html>
```

We have the `Foo` and `Bar` components.

They are defined by creating a promise that resolves to the component definition.

With Webpack, we can also use the `import` function to import our component.

For example, we can write:

```
import('./Foo.vue')
```

`import` returns a promise that resolves to the component, and it works the same way as the promise definition above.

### Grouping Components in the Same Chunk

We can group components in the same chunk bu creating components with functions:

```
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
```

We have comments with `webpackChunkName` with the chunk name.

### Navigation Failures

We can handle navigation errors with programmatic navigation.

For example, we can write:

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://unpkg.com/vue-router@4.0.0-beta.7/dist/vue-router.global.js"></script>
    <title>App</title>
  </head>
  <body>
    <div id="app">
      <p>
        <router-link to="/foo">foo</router-link>
        <a href="#" [@click](http://twitter.com/click "Twitter profile for @click").stop="go">bar</a>
      </p>
      <router-view></router-view>
    </div>
    <script>
      const Foo = {
        template: `<div>foo</div>`
      };

      const Bar = {
        template: `<div>bar</div>`,
        beforeRouteEnter(to, from, next) {
          next(new Error());
        }
      };

      const routes = [
        {
          path: "/foo",
          component: Foo
        },
        {
          path: "/bar",
          component: Bar
        }
      ];
      const router = VueRouter.createRouter({
        history: VueRouter.createWebHistory(),
        routes
      });
      const app = Vue.createApp({
        methods: {
          go() {
            this.$router.push("/bar").catch((failure) => {
              console.log(failure);
            });
          }
        }
      });
      app.use(router);
      app.mount("#app");
    </script>
  </body>
</html>
```

to handle navigation errors.

We a `beforeRouterEnter` method in the `Bar` component.

It calls `next` with an `Error` instance within the method.

This will cause the `Error` instance to be shown in the console.

In the root Vue instance, we have the `go` method that tries to go to the `/bar` route with the `push` method.

The `catch` method’s callback has the `failure` parameter that has the `Error` instance that’s thrown.

### Conclusion

We can change scrolling behavior to be async.

Also, components can be grouped into chunks and lazy-loaded.

Finally, we can handle errors that are raised from programmatic navigation.