Data Fetching

Sometimes you need to fetch data from the server when a route is activated. For example, before rendering a user profile, you need to fetch the user’s data from the server. We can achieve this in two different ways:

  • Fetching After Navigation: perform the navigation first, and fetch data in the incoming component’s lifecycle hook. Display a loading state while data is being fetched.

  • Fetching Before Navigation: Fetch data before navigation in the route enter guard, and perform the navigation after data has been fetched.

Technically, both are valid choices - it ultimately depends on the user experience you are aiming for.

Fetching After Navigation

When using this approach, we navigate and render the incoming component immediately, and fetch data in the component’s created hook. It gives us the opportunity to display a loading state while the data is being fetched over the network, and we can also handle loading differently for each view.

Let’s assume we have a Post component that needs to fetch the data for a post based on $route.params.id:

  1. <template>
  2. <div class="post">
  3. <div v-if="loading" class="loading">Loading...</div>
  4. <div v-if="error" class="error">{{ error }}</div>
  5. <div v-if="post" class="content">
  6. <h2>{{ post.title }}</h2>
  7. <p>{{ post.body }}</p>
  8. </div>
  9. </div>
  10. </template>
  1. export default {
  2. data() {
  3. return {
  4. loading: false,
  5. post: null,
  6. error: null,
  7. }
  8. },
  9. created() {
  10. // watch the params of the route to fetch the data again
  11. this.$watch(
  12. () => this.$route.params,
  13. () => {
  14. this.fetchData()
  15. },
  16. // fetch the data when the view is created and the data is
  17. // already being observed
  18. { immediate: true }
  19. )
  20. },
  21. methods: {
  22. fetchData() {
  23. this.error = this.post = null
  24. this.loading = true
  25. // replace `getPost` with your data fetching util / API wrapper
  26. getPost(this.$route.params.id, (err, post) => {
  27. this.loading = false
  28. if (err) {
  29. this.error = err.toString()
  30. } else {
  31. this.post = post
  32. }
  33. })
  34. },
  35. },
  36. }

Fetching Before Navigation

With this approach we fetch the data before actually navigating to the new route. We can perform the data fetching in the beforeRouteEnter guard in the incoming component, and only call next when the fetch is complete:

  1. export default {
  2. data() {
  3. return {
  4. post: null,
  5. error: null,
  6. }
  7. },
  8. beforeRouteEnter(to, from, next) {
  9. getPost(to.params.id, (err, post) => {
  10. next(vm => vm.setData(err, post))
  11. })
  12. },
  13. // when route changes and this component is already rendered,
  14. // the logic will be slightly different.
  15. async beforeRouteUpdate(to, from) {
  16. this.post = null
  17. try {
  18. this.post = await getPost(to.params.id)
  19. } catch (error) {
  20. this.error = error.toString()
  21. }
  22. },
  23. }

The user will stay on the previous view while the resource is being fetched for the incoming view. It is therefore recommended to display a progress bar or some kind of indicator while the data is being fetched. If the data fetch fails, it’s also necessary to display some kind of global warning message.