// Tutorial //

Even More Advanced Routing with Vue: Data Fetching

Published on March 23, 2020
Default avatar
By Jim Toth
Developer and author at DigitalOcean.
Even More Advanced Routing with Vue: Data Fetching

In the last post, More Advanced Routing with Vue, we covered using Transitions with Vue Router. This time we’ll cover Data Fetching with Vue Router.

Data Fetching allows us to load asynchronous data in our routed components. We can also specify whether data is fetched before or after a component is loaded. Both of these strategies are equally viable but have different implementations. We’ll cover both.

Vue Project Setup

Since this is yet another post about advanced Vue Router techniques, we’ll assume you’re already familiar with the basic setup. However, let’s define a starting point that we’ll use for the rest of the post:

# Yarn
$ yarn add vue-router

# npm
$ npm install vue-router --save
main.js
import Vue from 'vue';
import VueRouter from 'vue-router';

import App from './App';
import Swamp from './components/Swamp';
import Gator from './components/Gator';

Vue.use(VueRouter);

const router = new VueRouter({
  routes: [
    { path: '/swamp', component: Swamp },
    { path: '/gator', component: Gator }
  ]
});

new Vue({
  render: h => h(App),
  router
}).$mount('#app')
App.vue
<template>
  <div id="app">
    <div class="nav">
      <router-link to="/swamp">Swamp</router-link> |
      <router-link to="/gator">Gator</router-link>
    </div>
    <hr />
    <div class="router-view">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default { name: 'App' }
</script>
components/Swamp.vue
<template>
  <div>Welcome to the Swamp, {{ name }}!</div>
</template>

<script>
export default {
  name: 'Swamp',
  data() {
    return { name: null }
  },
}
</script>
components/Gator.vue
<template>
  <div>Howdy, Gator {{ name }}!</div>
</template>

<script>
export default {
  name: 'Gator',
  data() {
    return { name: null }
  }
}
</script>

Data Fetching

Let’s say we had a function that mocked a simple HTTP GET called pretendGet():

scripts/pretendGet.js
export default (callback) => {
  setTimeout(() => {
    callback(null, 'Alice');
  }, 500);
}

After 500ms pretendGet() will return the string 'Alice' to the callback method callback. We’ll use this to mock a server request in the following examples.

Fetching before navigation

Fetching before navigation allows us to ensure that our routed components have the data they need before being displayed to the user. In this approach we added a beforeRouteEnter method which Vue Router calls when the user requests to navigate to this component but before it has loaded. We also define a beforeRouteUpdate method which is called when the route changes. This is useful if you’re fetching data related to a route parameter which is accessible via to.params.

components/Gator.vue
import pretendGet from '../scripts/pretendGet';

export default {
  name: 'Gator',
  data() {
    return { name: null }
  },
  // Component not loaded yet
  beforeRouteEnter(to, from, next) {
    pretendGet((err, name) => {
      next(vm => vm.setName(err, name));
    });
  },
  // Component already loaded and route changes
  beforeRouteUpdate(to, from, next) {
    this.name = null;
    pretendGet((err, name) => {
      this.setName(err, name);
      next();
    });
  },
  methods: {
    setName(err, name) {
      if (err) {
        console.error(err);
      } else {
        this.name = name;
      }
    }
  }
}

Keep in mind that navigation will not happen until data is fetched. Because of this, it’s a good idea to display some kind of progress bar or indicator that data is being fetched. If there’s an error, it would also be a good idea to display that as well.

Fetching after navigation

Fetching after navigation is also a valid approach. In this case we’ll utilize the created() lifecycle hook to call our data fetching method fetchName(). We’ll also define a watch property on $route so we can call fetchName() whenever the route changes.

components/Swamp.vue
import pretendGet from '../scripts/pretendGet';

export default {
  name: 'Swamp',
  data() {
    return { name: null }
  },
  created() {
    this.fetchName();
  },
  watch: {
    // Re-fetch when route changes
    '$route': 'fetchName'
  },
  methods: {
    fetchName() {
      pretendGet((err, name) => {
        if (err) {
          console.error(err);
        } else {
          this.name = name;
        }
      });
    }
  }
}

Keep in mind that with this approach we’ll have to account for data not being ready when the component is first rendered. It’s a good idea to include placeholders or skeleton placeholders along with indicators to let the user know that data is being fetched along with any errors that might occur.

Wrapping Up

Vue Router Data Fetching is a great way to ensure a smooth user experience for your components that rely on fetching data from external sources. Fetching before navigation is a good approach if you’re a fan of using app-wide notifications or progress indicators. If you’d rather handle this kind of stuff on a component level then fetching after navigation might be the right approach for you. As always, make sure to read the docs!


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Jim Toth

author

Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment