Pinia Store状态缓存异常:手动修改LocalStorage后状态不更新
问题:Pinia状态与LocalStorage手动删除后不同步,路由守卫获取旧状态
调用auth.js中的logout函数时,状态与LocalStorage能正常同步更新;但手动在Chrome开发者工具中删除LocalStorage内的session、token、user及isEmailVerified数据后,Pinia状态并未更新,路由守卫获取的仍是旧状态。
相关代码
auth.js Pinia Store代码
import { defineStore } from 'pinia'; import { useShowStore } from '@/store/showStore'; export const useAuthStore = defineStore({ id: 'auth', state: () => ({ user: JSON.parse(localStorage.getItem('user')) || null, session: JSON.parse(localStorage.getItem('session')) || null, token: localStorage.getItem('token') || null, isEmailVerified: JSON.parse(localStorage.getItem('isEmailVerified')) || false, }), getters: { isAuthenticated: () => !!localStorage.getItem('token') || null, }, actions: { async login(email, password) { // ...
logout函数代码
async logout() { this.user = null; this.session = null; this.token = null; this.isEmailVerified = false; // Clear local storage localStorage.removeItem('user'); localStorage.removeItem('session'); localStorage.removeItem('token'); localStorage.removeItem('isEmailVerified'); const showStore = useShowStore(); showStore.closeMenu(); },
路由守卫代码
router.beforeEach((to, from, next) => { const authStore = useAuthStore(); //here it prints session after removing manually console.log('Is Authenticated:', authStore.isAuthenticated); if (to.meta.requiresAuth && !authStore.isAuthenticated) { next('/SignIn'); // Redirect to SignIn if not authenticated } else if (to.meta.approachOnlyLoggedOut && authStore.isAuthenticated && authStore.isEmailVerified) { next('/'); // Redirect to dashboard if authenticated and email verified } else if (authStore.isAuthenticated && !authStore.isEmailVerified && to.path !== '/EmailVerification') { if (to.path == '/VerifyEmail') { next(); } else { next('/EmailVerification'); // Redirect to EmailVerification if email is not verified } } else { next(); } });
解决方案
核心原因是Pinia的state仅在初始化时读取LocalStorage,手动修改LocalStorage不会自动触发状态更新。以下是两种中心化的处理方案:
方案1:监听LocalStorage及页面可见性变化,自动同步状态
在auth store中添加监听逻辑,当LocalStorage变化或页面重新可见时,自动将LocalStorage数据同步到Pinia状态,确保状态始终一致。
修改后的auth.js代码:
import { defineStore } from 'pinia'; import { useShowStore } from '@/store/showStore'; export const useAuthStore = defineStore({ id: 'auth', state: () => ({ user: JSON.parse(localStorage.getItem('user')) || null, session: JSON.parse(localStorage.getItem('session')) || null, token: localStorage.getItem('token') || null, isEmailVerified: JSON.parse(localStorage.getItem('isEmailVerified')) || false, }), getters: { // 改为基于state判断,避免和LocalStorage逻辑分歧 isAuthenticated: (state) => !!state.token, }, actions: { async login(email, password) { // ... 原有登录逻辑 }, async logout() { this.user = null; this.session = null; this.token = null; this.isEmailVerified = false; localStorage.removeItem('user'); localStorage.removeItem('session'); localStorage.removeItem('token'); localStorage.removeItem('isEmailVerified'); const showStore = useShowStore(); showStore.closeMenu(); }, // 同步LocalStorage到Pinia状态的方法 syncLocalStorageToState() { this.user = JSON.parse(localStorage.getItem('user')) || null; this.session = JSON.parse(localStorage.getItem('session')) || null; this.token = localStorage.getItem('token') || null; this.isEmailVerified = JSON.parse(localStorage.getItem('isEmailVerified')) || false; } }, created() { // 监听LocalStorage变化(同域其他页面修改时触发) const handleStorageChange = () => { this.syncLocalStorageToState(); }; window.addEventListener('storage', handleStorageChange); // 监听页面可见性,切回页面时同步(手动修改后切回页面触发) const handleVisibilityChange = () => { if (document.visibilityState === 'visible') { this.syncLocalStorageToState(); } }; document.addEventListener('visibilitychange', handleVisibilityChange); // 销毁store时移除监听,避免内存泄漏 this.$onDestroy(() => { window.removeEventListener('storage', handleStorageChange); document.removeEventListener('visibilitychange', handleVisibilityChange); }); } });
方案2:路由守卫触发前主动同步状态
如果不想用监听,可在路由守卫最开始主动调用同步方法,确保每次路由跳转时都获取最新状态:
修改路由守卫代码:
router.beforeEach((to, from, next) => { const authStore = useAuthStore(); // 主动同步LocalStorage到Pinia状态 authStore.syncLocalStorageToState(); console.log('Is Authenticated:', authStore.isAuthenticated); if (to.meta.requiresAuth && !authStore.isAuthenticated) { next('/SignIn'); } else if (to.meta.approachOnlyLoggedOut && authStore.isAuthenticated && authStore.isEmailVerified) { next('/'); } else if (authStore.isAuthenticated && !authStore.isEmailVerified && to.path !== '/EmailVerification') { if (to.path == '/VerifyEmail') { next(); } else { next('/EmailVerification'); } } else { next(); } });
注意事项
原getter中的isAuthenticated直接读取LocalStorage,容易导致和Pinia state不一致,建议改为基于state判断,保持逻辑统一。
内容的提问来源于stack exchange,提问作者Milan Milosevic
相关产品推荐
相关产品推荐

