#vue.js #vuex #vue-router
#vue.js #vuex #vue-маршрутизатор
Вопрос:
У меня есть настройка маршрутизатора Vuex и Vue. Я хочу показать страницу настройки на случай, если учетная запись пользователя настроена неправильно. Это реализуется путем выполнения вызова API для серверной части. Результат сохраняется внутри Vuex и доступен с помощью геттера. Действие отправляется beforeCreate
в корневом экземпляре Vuex:
new Vue({
router,
store,
render: h => h(App),
beforeCreate() {
this.$store.dispatch("config/get");
}
}).$mount("#app");
Тем не менее, мой маршрутизатор beforeEach
никогда не получает true
, но получатель определенно возвращается true
в соответствии с DevTools:
router.beforeEach((to, next) => {
if (!to.matched.some(record => record.meta.requiresSetup)) {
next();
return;
}
if (!store.getters["config/isConfigured"]) { // Executed every time.
next("/setup");
return;
}
next();
});
Ответ №1:
Задержка загрузки приложения
Невозможно использовать перехват жизненного цикла для задержки загрузки, даже если перехват отмечен async
и выполняет await
для некоторой асинхронной операции. Хуки не предназначены для разрешения манипуляций, только для предоставления доступа к этапам.
Тем не менее, вы можете отложить приложение, просто не загружая его до завершения действия магазина, но понимаете, что это означает пустую страницу для пользователя, что является плохим пользовательским опытом. Но вот как вы можете это сделать:
main.js
const preload = async () => {
await store.dispatch('config/get'); // `await` store action which returns a promise
new Vue({
store,
router,
render: (h) => h(App)
}).$mount("#app");
}
preload();
console.log('LOADING...');
Лучший способ
Лучше отправить действие, а не ждать его. Пусть App.vue загружается и используется v-if
для отображения заставки, пока какое-либо состояние хранилища isLoading
не будет false
:
main.js
store.dispatch('config/get');
new Vue({
store,
router,
render: (h) => h(App)
}).$mount("#app");
App.vue
<template>
<div>
<div v-if="isLoading">
LOADING... <!-- Attractive splash screen here -->
</div>
<div v-else>
<router-view></router-view> <!-- Don't show the router view until ready -->
</div>
</div>
</template>
Полностью удалите навигационную защиту и в App.vue установите часы isLoading
. Как только он больше не загружается, перенаправьте на основе состояния средства получения учетной записи:
computed: {
...mapState(['isLoading'])
},
methods: {
redirect() {
const path = this.$route.path;
if (!this.$store.getters["config/isConfigured"]) {
path !== '/setup' amp;amp; this.$router.push({ path: '/setup' });
} else {
path !== '/' amp;amp; this.$router.push({ path: '/' });
}
}
},
watch: {
isLoading(val) {
if (val === false) {
this.redirect();
}
}
}
Комментарии:
1. Интересное решение. К сожалению, я не могу заставить его работать. Как только
loading
становитсяfalse
, я перенаправляюсь на/setup
. Наблюдатель кажется избыточным. Выдает ошибку «дублирование навигации».2. Вы можете проверить текущий маршрут через
to.path
(в guard) илиthis.$route.path
(в component), чтобы избежать избыточной маршрутизации.beforeEach
Кстати, ваши аргументы тоже неверны(to, from, next)
. Существуют варианты этого ответа, которые могут быть лучше для того, что вам нужно. Вы можете снять навигационную защиту или снять часы. Вы можете удалить часы и проверятьisLoading
только охрану — перенаправление на/setup
, если приложение все еще загружается.
Ответ №2:
Эти обратные вызовы жизненного цикла имеют синхронное поведение. что вы можете сделать, это что-то вроде
store.dispatch("config/get").then(() => {
router.beforeEach((to, from, next) => {...}
new Vue({...})
})
или вы можете вызвать его перед каждым маршрутизатором и сохранить некоторое состояние, например, isLoaded и call store. отправка только один раз при первом вызове, а для остальной части вызова используйте сохраненное состояние