Vuex 数据刷新丢失是浏览器机制所致,解决关键是在 App.vue 中用 onLaunch(首次初始化)和 onShow(兜底恢复)统一接管状态恢复,配合 uni.setStorage 持久化与拦截器懒读取设计。

刷新后 Vuex 数据丢失是必然的——因为内存清空,不是 bug,是浏览器机制。解决的关键不是“阻止丢失”,而是“丢失后自动恢复”,且必须在 App.vue 生命周期里统一接管,不能散落在各页面。
为什么 onLaunch + onShow 是唯一可靠入口
uni-app 的 H5、小程序、App 三端启动逻辑不一致:onLaunch 只触发一次(首次加载),onShow 每次页面可见都触发(含刷新、切后台再切回、从其他页返回)。只靠 onLaunch 会漏掉 H5 刷新场景;只靠页面级 onShow 会导致多页面重复恢复、token 注入冲突、请求拦截器未就绪等问题。
-
onLaunch用于首次初始化:读缓存 + 注入全局状态 + 设置请求拦截器基础结构 -
onShow用于兜底恢复:重新拉取最新 token / 用户信息(可选),并确保拦截器 header、Pinia/Vuex state、uni.$u.token等全部同步 - 不要在
main.js或组件onLoad中读取 storage —— uni API 尚未就绪或执行时机错位
用 sessionStorage 还是 uni.setStorage?
优先用 uni.setStorage(即小程序的异步本地存储)而非 sessionStorage,原因很实际:
-
uni.setStorage在 H5、小程序、App 三端行为一致;sessionStorage在微信小程序中不可用,H5 下关闭标签页即丢失,不符合“用户登录态应跨标签页延续”的常见需求 -
uni.getStorageSync('token')在所有平台都可用,且值在刷新后依然存在——问题从来不在“存不住”,而在“没人去读它并塞进状态树” - 如果项目只跑 H5,
localStorage更合适(持久);若含小程序,必须用uni.setStorage
mutation 里手动存 storage 太累?用插件或 Proxy 封装
每个 mutation 都写 uni.setStorage 不仅冗余,还容易漏写、类型处理出错。更稳的方式是封装一层:
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
立即学习“前端免费学习笔记(深入)”;
- 推荐
vuex-persistedstate(配合自定义storage对象):plugins: [ createPersistedState({ storage: { getItem: key => uni.getStorageSync(key), setItem: (key, value) => uni.setStorageSync(key, value), removeItem: key => uni.removeStorageSync(key) } }) ] - 或用 Proxy 自动劫持 state 赋值(适合轻量项目):在 store 初始化时对
state做代理,set时自动序列化存入uni.setStorageSync,同时兼容对象/数组/基本类型 - 避免直接操作
sessionStorage.setItem后再手动JSON.parse—— uni-app 中无原生sessionStorageAPI,强行调用在小程序端会报错
别忘了请求拦截器的“懒读取”设计
即使 Vuex 状态恢复了,如果请求拦截器里的 config.header.Authorization 还是写死读 uni.getStorageSync,第一次请求仍会 401——因为拦截器初始化早于 onShow 执行。
- 正确做法:拦截器里从响应式变量取值,比如
store.state.auth.token或uni.$u.token -
restoreToken()函数负责更新这个变量,确保后续每次请求都能拿到最新值 - 加空值防御:若变量为空,跳转登录页或 throw Error,而不是发裸请求
真正难的不是“怎么存”,而是“什么时候读、从哪读、谁来触发读、读完喂给谁”。所有环节断一环,刷新后状态就卡在半途。最易被忽略的是拦截器与状态恢复的时序差——它不会报错,只会静默发一堆 401。

















