Vue.js 如何让Vue路由器防护等待Vuex?
所以,我在公开场合找到的关于这个问题的所有答案都不是很有帮助,尽管这些答案“有效”,但它们都非常粗糙 基本上,我有一个vuex变量,Vue.js 如何让Vue路由器防护等待Vuex?,vue.js,vuex,vue-router,Vue.js,Vuex,Vue Router,所以,我在公开场合找到的关于这个问题的所有答案都不是很有帮助,尽管这些答案“有效”,但它们都非常粗糙 基本上,我有一个vuex变量,appLoading,它最初为true,但在所有异步操作完成后设置为false。我还有另一个名为user的vuex变量,它包含异步操作返回后发送的用户信息 然后,我还有一个路由器守卫,负责检查 router.beforeEach((to, from, next) => { if (to.matched.some(route => route.meta
appLoading
,它最初为true,但在所有异步操作完成后设置为false。我还有另一个名为user
的vuex变量,它包含异步操作返回后发送的用户信息
然后,我还有一个路由器守卫,负责检查
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.requiresAuth)) {
if (store.getters.getUser) {
return next();
}
return router.push({ name: 'index.signup' });
}
return next();
});
在我的初始Vue实例中,我随后显示加载状态,直到appLoading=false代码>
现在这个“工作”,但有一个问题,这是真正困扰我。如果你加载页面,你会看到你应该看到的另一个页面的“闪烁”
所以,如果您登录,在第一次加载时,您将看到注册页面的闪烁。如果您没有登录,您将看到登录页面闪烁
这是相当恼人的,我把问题缩小到我的授权保护。
由于用户
不存在,它似乎正在将注册页面推送到路由器,然后由于用户
被提交,它立即推送到登录页面
我如何才能以一种不被黑客攻击的方式解决这个问题,因为Vue对于这样一个常见的问题甚至连一点官方文档/示例都没有,这有点烦人,有点令人沮丧,尤其是因为如此大量的Web应用程序使用身份验证
希望有人能提供一些帮助。:) 根据评论中的讨论:
对于您的案例,最好的方法是将您的appLoading
变量设置为promise
。这就是你可以做事情或等待事情的方式,直到你的应用程序数据被解析
考虑到appLoading
一个您用api调用承诺初始化的承诺,您的路由器挂钩将如下所示:
router.beforeEach((to, from, next) => {
appLoading.then(() => {
if (to.matched.some(route => route.meta.requiresAuth)) {
if (store.getters.getUser) {
return next();
}
return router.push({ name: "index.signup" });
}
return next();
});
});
您可能只想将它作为导出保存在init
代码中,而不是保存在Vuex中。Vuex用于通过组件共享的反应式数据。每个钩子之前的路由器可以是一个承诺,并等待Vuex操作完成。比如:
router.beforeEach(async (to, from, next) => {
if (to.matched.some(route => route.meta.requiresAuth)) {
await store.dispatch('init');
if (store.getters.getUser) {
return next();
}
return router.push({ name: 'index.signup' });
}
return next();
});
“init”操作应返回一个承诺:
const actions = {
async init({commit}) {
const user = await service.getUser();
commit('setUser', user);
}
}
这种方法存在的问题是,每当我们导航到一个给定的页面时,它都会触发“init”操作,该操作将从服务器获取用户。我们只想在没有用户的情况下获取用户,因此我们可以更新存储检查,如果它有用户,则按照以下顺序获取:
const state = {
user: null
}
const actions = {
async init({commit, state}) {
if(!state.user) {
const user = await service.getUser();
commit('setUser', user);
}
}
}
你的appLoading
实际上应该是一个promise
,你可以在你的hooks@pranavjindal999默认情况下是这样的吗?是真实的状态本身是一个承诺,还是一个获得者?假设它是getter,我能用一个if语句包装我的路由器保护吗`如果(store.getters.appLoading){guard…}?如果希望直接使用getter或state访问它,则由您决定。但你描述的方式行不通。Hooks不知道你的状态何时改变。你必须让它成为承诺,然后
把整个钩子都钩住承诺。@pranavjindal999我不确定我是否遵守。我想我知道大概的意思,但你能举个小例子吗?谢谢:)嘿,像这样的东西行吗<代码>导出常量init=newpromise((解析,拒绝)=>{if(store.getters.appisload==false){resolve();}else{reject();})代码>我希望你能提供更多关于承诺包装部分的信息。我尝试了许多不同的方法,但都没有成功/你似乎缺乏对承诺的理解。我建议你重新审视承诺。好资源:问题在于路由器。beforeach
钩子在存储操作之前执行。问题的答案是根据存储中appLoading
状态的值,从这个钩子内部调用操作。如果未定义,则调用操作;如果为true,则查看存储;如果为false,则表示您想要的状态已提交。您需要使用async/await或Promise.then()