|
| 1 | +# Async Routes |
| 2 | + |
| 3 | +Sometimes you need to fetch data from the server before rendering a route. For |
| 4 | +example, before visiting a user profile, you have to fetch his data from the |
| 5 | +server. We can achieve this in two different ways. Each way provide a different |
| 6 | +UX approach and both of them are valid designs. |
| 7 | + |
| 8 | + |
| 9 | +## Fetching before navigation |
| 10 | + |
| 11 | +This method consists on fetching the data before actually navigating to the new |
| 12 | +route. For those using vue-router 1, this works as the `activate` hook. In |
| 13 | +vue-router 2 you use the `beforeRouteEnter` hook to control the navigation flow. |
| 14 | +You get access to the `route`, a `redirect` function and a `next` callback to |
| 15 | +let the navigation end. Not calling the `next` callback will simply cancel the |
| 16 | +navigation. Note that this hook is |
| 17 | + |
| 18 | +``` js |
| 19 | +export default { |
| 20 | + data () { |
| 21 | + return { |
| 22 | + loading: false, |
| 23 | + post: null, |
| 24 | + error: null |
| 25 | + } |
| 26 | + }, |
| 27 | + beforeRouteEnter (route, redirect, next) { |
| 28 | + // fetch the data when the view is created and the data is |
| 29 | + // already being observed |
| 30 | + this.fetchData(route.params.id, next) |
| 31 | + }, |
| 32 | + watch: { |
| 33 | + // call again the method if the route changes |
| 34 | + $route () { |
| 35 | + this.fetchData(this.$route.params.id) |
| 36 | + } |
| 37 | + }, |
| 38 | + methods: { |
| 39 | + fetchData (id, cb) { |
| 40 | + this.error = this.post = null |
| 41 | + this.loading = true |
| 42 | + getPost(id, (err, post) => { |
| 43 | + this.loading = false |
| 44 | + if (err) { |
| 45 | + this.error = err.toString() |
| 46 | + } else { |
| 47 | + this.post = post |
| 48 | + } |
| 49 | + cb && cb() |
| 50 | + }) |
| 51 | + } |
| 52 | + } |
| 53 | +} |
| 54 | +``` |
| 55 | + |
| 56 | +The user still can use the application while the resource is being fetched. It |
| 57 | +is therefore recommended to show him with a progress bar or any other indicator |
| 58 | +that the web site is waiting for data. If, during this time, the user navigates |
| 59 | +somewhere else by clicking on a link, the navigation waiting for data will never |
| 60 | +take place. |
| 61 | + |
| 62 | +## Fetching inside the view |
| 63 | + |
| 64 | +This method consists on fetching data during the component lifecycle. It allows |
| 65 | +you to define how the content of your view is presented while the resources are |
| 66 | +loading. Using this approach let you handle how loading in handled differently |
| 67 | +for each view. |
| 68 | + |
| 69 | +Replacing `beforeRouteEnter` with `created` is almost all you need to do to |
| 70 | +switch to the other fetching method. |
| 71 | + |
| 72 | +``` js |
| 73 | +export default { |
| 74 | + data () { |
| 75 | + return { |
| 76 | + loading: false, |
| 77 | + post: null, |
| 78 | + error: null |
| 79 | + } |
| 80 | + }, |
| 81 | + created () { |
| 82 | + // fetch the data when the view is created and the data is |
| 83 | + // already being observed |
| 84 | + this.fetchData() |
| 85 | + }, |
| 86 | + watch: { |
| 87 | + // call again the method if the route changes |
| 88 | + '$route': 'fetchData' |
| 89 | + }, |
| 90 | + methods: { |
| 91 | + fetchData () { |
| 92 | + this.error = this.post = null |
| 93 | + this.loading = true |
| 94 | + getPost(this.$route.params.id, (err, post) => { |
| 95 | + this.loading = false |
| 96 | + if (err) { |
| 97 | + this.error = err.toString() |
| 98 | + } else { |
| 99 | + this.post = post |
| 100 | + } |
| 101 | + }) |
| 102 | + } |
| 103 | + } |
| 104 | +} |
| 105 | +``` |
| 106 | + |
| 107 | +The component lifecycle will go on and once the data is fetched, the view will update acordingly. This way you can choose what to show while the data is being fetched. Here we're just displaying _Loading..._: |
| 108 | + |
| 109 | +``` html |
| 110 | +<template> |
| 111 | + <div class="post"> |
| 112 | + <div class="loading" v-if="loading">Loading...</div> |
| 113 | + <div v-if="error" class="error"> |
| 114 | + {{ error }} |
| 115 | + </div> |
| 116 | + <transition name="slide"> |
| 117 | + <!-- |
| 118 | + giving the post container a unique key triggers transitions |
| 119 | + when the post id changes. |
| 120 | + --> |
| 121 | + <div v-if="post" class="content" :key="post.id"> |
| 122 | + <h2>{{ post.title }}</h2> |
| 123 | + <p>{{ post.body }}</p> |
| 124 | + </div> |
| 125 | + </transition> |
| 126 | + </div> |
| 127 | +</template> |
| 128 | +``` |
0 commit comments