Even More Advanced Routing with Vue: Data Fetching

Jim Toth

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!

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#