Загрузка данных
Иногда при активации маршрута требуется получить данные с сервера. Например, перед отображением профиля пользователя необходимо получить данные о нем с сервера. Этого можно добиться двумя различными способами:
Получение данных после перехода: сначала перейти к новому маршруту, а затем получить данные в хуке жизненного цикла компонента маршрута. По мере загрузки данных отображать индикатор состояния загрузки.
Получение данных перед переходом: Получение данных перед переходом в навигационном хуке маршрутаи и завершение навигации уже когда они будут получены.
С технической точки зрения, оба варианта являются правильными - в конечном итоге все зависит от того, какой UX (user expirience) вы хотите получить.
Получение данных после перехода
При таком подходе мы сразу же осуществляем переход и рендеринг компонента маршрута, а данные получаем в хуке created
компонента. Это дает нам возможность отображать состояние загрузки, пока данные пересылаются по сети, а также по-разному обрабатывать загрузку для каждого представления.
Предположим, что у нас есть компонент Post
, которому необходимо получить данные для поста на основе $route.params.id
:
<template>
<div class="post">
<div v-if="loading" class="loading">Loading...</div>
<div v-if="error" class="error">{{ error }}</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
<template>
<div class="post">
<div v-if="loading" class="loading">Loading...</div>
<div v-if="error" class="error">{{ error }}</div>
<div v-if="post" class="content">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
export default {
data() {
return {
loading: false,
post: null,
error: null,
}
},
created() {
// следить за изменениями параметров маршрута
// для повторной загрузки данных
this.$watch(
() => this.$route.params,
() => {
this.fetchData()
},
// получать данные, когда представление создано и данные
// уже реактивно отслеживаются
{ immediate: true }
)
},
methods: {
fetchData() {
this.error = this.post = null
this.loading = true
// замените `getPost` на вашу утилиту для
// получения данных / доступа к API
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
},
},
}
export default {
data() {
return {
loading: false,
post: null,
error: null,
}
},
created() {
// следить за изменениями параметров маршрута
// для повторной загрузки данных
this.$watch(
() => this.$route.params,
() => {
this.fetchData()
},
// получать данные, когда представление создано и данные
// уже реактивно отслеживаются
{ immediate: true }
)
},
methods: {
fetchData() {
this.error = this.post = null
this.loading = true
// замените `getPost` на вашу утилиту для
// получения данных / доступа к API
getPost(this.$route.params.id, (err, post) => {
this.loading = false
if (err) {
this.error = err.toString()
} else {
this.post = post
}
})
},
},
}
Получение данных перед переходом
При этом подходе мы запрашиваем данные до завершения перехода к новому маршруту. Получение данных выполняется в навигационном хуке beforeRouteEnter
в компоненте марштура, который вызывает метод next
, когда данные получены. Коллбек, передаваемый в next
, будет вызван после монтирования компонента:
export default {
data() {
return {
post: null,
error: null,
}
},
beforeRouteEnter(to, from, next) {
getPost(to.params.id, (err, post) => {
// `setData` - это метод, определенный ниже
next(vm => vm.setData(err, post))
})
},
// когда маршрут изменяется, а этот компонент уже отрисован,
// логика будет несколько иной.
async beforeRouteUpdate(to, from) {
this.post = null
try {
this.post = await getPost(to.params.id)
} catch (error) {
this.error = error.toString()
}
},
methods: {
setData(error, post) {
if (error) {
this.error = error
} else {
this.post = post
}
}
}
}
export default {
data() {
return {
post: null,
error: null,
}
},
beforeRouteEnter(to, from, next) {
getPost(to.params.id, (err, post) => {
// `setData` - это метод, определенный ниже
next(vm => vm.setData(err, post))
})
},
// когда маршрут изменяется, а этот компонент уже отрисован,
// логика будет несколько иной.
async beforeRouteUpdate(to, from) {
this.post = null
try {
this.post = await getPost(to.params.id)
} catch (error) {
this.error = error.toString()
}
},
methods: {
setData(error, post) {
if (error) {
this.error = error
} else {
this.post = post
}
}
}
}
Пользователь останется на предыдущем представлении, пока данные будут загружаться на новом. Поэтому рекомендуется отображать индикатор загрузки или какой-либо другой индикатор, пока данные загружаются. Если получение данных завершается неудачей, необходимо отображать какое-либо глобальное предупреждение.