查看: 88|回复: 0

Vue刷新页面Vuex状态丢失 持久化插件配置与退出清理

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
开发 Vue 项目时常见一个现象:路由跳转正常,但按下 F5 刷新后,Vuex 中的 token、userInfo、searchForm 全部回到初始值。排查后确认不是业务代码 bug,而是 Vuex 的设计使然——state 只保存在内存中,刷新页面会销毁当前应用进程并重新创建 store,内存数据自然被重置。如果每次刷新都重新请求接口恢复状态,既增加请求也可能出现页面闪烁。

针对这个问题,一条较为稳妥的落地路径是:用 vuex-persistedstate 把需要保留的 state 缓存到 localStorage,初始化时自动读回。下面是配置与几个容易踩坑的细节。

一、安装与 Store 配置

安装命令:
  1. npm install vuex-persistedstate --save
复制代码

在 store/index.js 中引入插件并在 plugins 中启用,key 用于指定 localStorage 的缓存键名:
  1. import Vue from 'vue'
  2. import Vuex from 'vuex'
  3. import persistedState from 'vuex-persistedstate'
  4. Vue.use(Vuex)
  5. export default new Vuex.Store({
  6.   state: {
  7.     token: '',
  8.     userInfo: {},
  9.     searchForm: {}
  10.   },
  11.   mutations: {},
  12.   actions: {},
  13.   // 配置持久化
  14.   plugins: [persistedState({ key: 'vuex_cache' })]
  15. })
复制代码

这段配置的含义是:插件会自动把 store.state 序列化写入 localStorage 的 vuex_cache 键,并在应用启动时读取该键恢复 state。配置完成后刷新页面,token、用户信息等不再丢失,也不需要重复调用接口,页面不会因等待接口而闪烁。该方案配置量小、对业务代码侵入低,适合 Vue2 常规项目。

二、避坑一:不要全量持久化

使用持久化插件时,不要把所有 state 都缓存下来。列表数据、临时弹窗状态、实时动态数据不适合缓存,这类数据变化频繁、时效性强,缓存后容易产生脏数据,甚至导致页面状态错乱。实践上只保留 token、用户信息、全局固定配置等真正需要跨刷新复用的字段即可。这里的核心原则是:不要全量持久化。

三、避坑二:退出登录必须手动清缓存

只清空 Vuex state 并不够,localStorage 中的 vuex_cache 仍然保留旧数据,重新进入页面时插件会把旧 token 和用户信息读回来,造成登录状态异常。退出登录时应同时重置 store 并删除缓存键:
  1. logout() {
  2.   this.$store.commit('resetState')
  3.   localStorage.removeItem('vuex_cache')
  4.   this.$router.replace('/login')
  5. }
复制代码

其中 resetState 是用于把 state 恢复到初始值的 mutation,vuex_cache 必须与 plugins 中配置的 key 保持一致。

四、其他方案与适用场景

如果项目使用 Pinia(Vue3 首选),可以换成 pinia-plugin-persistedstate:安装 npm i pinia-plugin-persistedstate,在 main.ts 中注册插件,然后在需要持久化的 Store 中开启 persist:
  1. import { defineStore } from 'pinia'
  2. export const useUserStore = defineStore('user', {
  3.   state: () => ({
  4.     token: '',
  5.     userInfo: null
  6.   }),
  7.   // 开启持久化
  8.   persist: true // 默认存 localStorage,刷新后自动恢复
  9. })
复制代码

若没有使用状态管理库,或只想保存某个关键变量,可以直接操作 Web Storage。核心逻辑是页面加载时读取、数据变化时写入:
  1. import { ref, watch, onMounted } from 'vue'
  2. export default {
  3.   setup() {
  4.     const keyword = ref('')
  5.     // 1. 页面加载时读取缓存
  6.     onMounted(() => {
  7.       const saved = localStorage.getItem('search_keyword')
  8.       if (saved) keyword.value = saved
  9.     })
  10.     // 2. 监听数据变化,实时存入缓存
  11.     watch(keyword, (newVal) => {
  12.       localStorage.setItem('search_keyword', newVal)
  13.     })
  14.     return { keyword }
  15.   }
  16. }
复制代码

这里需要区分两种存储:localStorage 是永久存储,关闭浏览器再打开仍在,适合 Token、用户信息;sessionStorage 是标签页级别,关闭该标签页即清除,适合表单暂存,能避免多标签页互相干扰。

如果需求只是路由切换后返回不丢数据,而不是 F5 刷新,应使用 Keep-Alive 缓存组件:在 router-view 外层包裹 keep-alive,被缓存组件会触发 activated 和 deactivated 生命周期,数据保留在内存中。但该方案无法抵抗浏览器刷新,因为刷新会重载整个页面。

对于列表页的搜索关键词、页码等,可以放进 URL 的 query 参数,例如 ?page=1&keyword=vue,刷新后路由参数不会丢失,在 created 钩子中读取 this.$route.query 即可恢复。缺点是不适合存 Token 或大对象,URL 长度有限,敏感信息也容易泄露。

五、选型建议

综合各方案的特点:Vue2 加 Vuex 的常规 SPA 项目,优先用 vuex-persistedstate,配置量最小;Vue3 加 Pinia 用 pinia-plugin-persistedstate;小型项目或只保存单个变量,手动读写 localStorage/sessionStorage 最直接;只涉及路由切换缓存用 Keep-Alive;筛选条件、分页参数放 URL query。关键仍是两点:按需持久化,退出登录同步清理缓存。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-24 16:28 , Processed in 0.026526 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部