在初始路由之前执行 Vuex 操作
Execute Vuex action before initial routing
我已经安装了 Vuex 和 Vue Router。我想显示一个设置页面,以防用户帐户设置不正确。这是通过对后端进行 API 调用来实现的。结果存储在 Vuex 中并使用 getter 访问。该动作在根 Vuex 实例的 beforeCreate
中调度:
new Vue({
router,
store,
render: h => h(App),
beforeCreate() {
this.$store.dispatch("config/get");
}
}).$mount("#app");
但是,我的路由器 beforeEach
从未收到 true
但 getter 肯定会根据 DevTools 返回 true
:
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();
});
这些生命周期回调具有同步行为。
你可以做的是
store.dispatch("config/get").then(() => {
router.beforeEach((to, from, next) => {...}
new Vue({...})
})
或者您可以在路由器的 beforeEach 中调用它并存储一些状态,如 isLoaded 并仅在 firstCall 上调用 store.dispatch 一次,其余调用使用存储的状态
延迟应用加载
无法使用生命周期挂钩来延迟加载,即使挂钩标记为 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
上放一个手表。一旦不再加载,根据帐户状态重定向 getter:
computed: {
...mapState(['isLoading'])
},
methods: {
redirect() {
const path = this.$route.path;
if (!this.$store.getters["config/isConfigured"]) {
path !== '/setup' && this.$router.push({ path: '/setup' });
} else {
path !== '/' && this.$router.push({ path: '/' });
}
}
},
watch: {
isLoading(val) {
if (val === false) {
this.redirect();
}
}
}
我已经安装了 Vuex 和 Vue Router。我想显示一个设置页面,以防用户帐户设置不正确。这是通过对后端进行 API 调用来实现的。结果存储在 Vuex 中并使用 getter 访问。该动作在根 Vuex 实例的 beforeCreate
中调度:
new Vue({
router,
store,
render: h => h(App),
beforeCreate() {
this.$store.dispatch("config/get");
}
}).$mount("#app");
但是,我的路由器 beforeEach
从未收到 true
但 getter 肯定会根据 DevTools 返回 true
:
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();
});
这些生命周期回调具有同步行为。 你可以做的是
store.dispatch("config/get").then(() => {
router.beforeEach((to, from, next) => {...}
new Vue({...})
})
或者您可以在路由器的 beforeEach 中调用它并存储一些状态,如 isLoaded 并仅在 firstCall 上调用 store.dispatch 一次,其余调用使用存储的状态
延迟应用加载
无法使用生命周期挂钩来延迟加载,即使挂钩标记为 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
上放一个手表。一旦不再加载,根据帐户状态重定向 getter:
computed: {
...mapState(['isLoading'])
},
methods: {
redirect() {
const path = this.$route.path;
if (!this.$store.getters["config/isConfigured"]) {
path !== '/setup' && this.$router.push({ path: '/setup' });
} else {
path !== '/' && this.$router.push({ path: '/' });
}
}
},
watch: {
isLoading(val) {
if (val === false) {
this.redirect();
}
}
}