Categories
Vue 3

Vue Router 4–Per-Route Transition and Fetch Data During Navigation

Spread the love

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.

Per-Route Transition

We can add transition effects for individual routes.

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>
    <style>
      .fade-enter-active,
      .fade-leave-active {
        transition: opacity 0.15s ease;
      }
      .fade-enter-from,
      .fade-leave-to {
        opacity: 0;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <p>
        <router-link to="/foo">foo</router-link>
        <router-link to="/bar">bar</router-link>
      </p>
      <router-view v-slot="{ Component, route }">
        <transition :name='route.path.includes("foo") ? `fade`:``'>
          <component :is="Component" />
        </transition>
      </router-view>
    </div>
    <script>
      const Foo = {
        template: "<div>foo</div>"
      };
      const Bar = {
        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 set the name prop dynamically by checking the route object.

The path property has the path of the route.

Therefore, we can check the path to set the value of name to the transition we want.

Data Fetching

We sometimes want to fetch data from the server when a route is activated.

This can be done with various hooks.

For instance, 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>foo</div>"
      };
      const Bar = {
        template: "<div>{{bar}}</div>",
        data() {
          return {
            bar: ""
          };
        },
        created() {
          this.fetchData();
        },
        watch: {
          $route: "fetchData"
        },
        methods: {
          async fetchData() {
            this.bar = "bar";
          }
        }
      };
      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 watch the $route object and call the fetchData method when $route changes.

Fetching Before Navigation

We can also run methods to fetch data in the before before navigation hooks.

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>
        <router-link to="/bar/1">bar 1</router-link>
        <router-link to="/bar/2">bar 2</router-link>
      </p>
      <router-view></router-view>
    </div>
    <script>
      const Foo = {
        template: "<div>foo</div>"
      };
      const Bar = {
        template: "<div>{{id}}</div>",
        data() {
          return {
            id: ""
          };
        },
        beforeRouteEnter(to, from, next) {
          next((vm) => vm.fetchData(to.params.id));
        },
        beforeRouteUpdate(to, from, next) {
          this.fetchData(to.params.id);
          next();
        },
        methods: {
          async fetchData(id) {
            this.id = id;
          }
        }
      };
      const routes = [
        {
          path: "/foo",
          component: Foo
        },
        {
          path: "/bar/:id",
          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 beforeRouterEnter and beforeRouteUpdate hooks that runs before the component is rendered and when the route params change respectively.

The fetchData method is run in the callback to get the data.

We have 2 router-link that goes to the /bar route with its own parameter.

We get the id parameter in the navigation guard methods and called fetchData to set its value to the this.id state.

Therefore, we’ll see them in the template.

Conclusion

We have a new way to add per-route transition with Vue Router 4.

Also, we can fetch data in Vue Router hooks with Vue Router 4.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *