在 Vue3 项目里使用 Pinia 管理用户状态时,常见现象是:调用过 setUsername 后当前页面显示正常,但浏览器刷新后 username 又变空。原因在原文现象中已经明确:Pinia 状态默认只保存在内存,页面刷新会重新初始化 Store;Store 里虽然写了 localStorage.setItem 做保存,但初始化时没有从 localStorage 读取恢复数据。
问题定位
原有逻辑只完成了“写入”这一半:setUsername 修改 username 并写入 localStorage,clearUser 清空 username 并移除 localStorage;但 username 初始值仍是 ref('')。因此刷新时 Store 重新创建,值回到空字符串,已经保存到 localStorage 的数据没有被读回。
方案一:手动补全初始化读取
如果当前只有 username 一个字段需要持久化,不需要安装插件,直接修改 stores/user.ts,把初始值改为从 localStorage 读取,没有值时回退为空字符串:
- import { defineStore } from 'pinia'
- import { ref } from 'vue'
- export const useUserStore = defineStore('user', () => {
- // 初始化时从 localStorage 读取,没有则默认空字符串
- const username = ref(localStorage.getItem('username') || '')
- function setUsername(name: string) {
- username.value = name
- localStorage.setItem('username', name)
- }
- function clearUser() {
- username.value = ''
- localStorage.removeItem('username')
- }
- return { username, setUsername, clearUser }
- })
复制代码
这段改动的核心只有初始化表达式:ref('') 改为 ref(localStorage.getItem('username') || '')。刷新后重新初始化 Store 时,会先从 localStorage 读取之前保存的用户名;setUsername 和 clearUser 仍分别负责写入和删除。适用场景是持久化字段很少、逻辑简单,手动维护读写成本低。
方案二:使用 pinia-plugin-persistedstate 插件
如果后续还要持久化 token、权限等更多状态,逐个字段手写 localStorage 容易遗漏。原文推荐使用 pinia-plugin-persistedstate,由插件自动处理存取。
第一步,安装插件:
- npm install pinia-plugin-persistedstate
复制代码
第二步,在 main.ts 中创建 Pinia 实例并注册插件:
- import { createApp } from "vue";
- import { createPinia } from "pinia";
- import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
- import App from "./App.vue";
- import router from "./router/index.ts";
- const app = createApp(App);
- const pinia = createPinia();
- pinia.use(piniaPluginPersistedstate); // 注册持久化插件
- app.use(pinia);
- app.use(router);
- app.mount("#app");
复制代码
第三步,在 Store 的第二个参数中开启 persist:
- import { defineStore } from 'pinia'
- import { ref } from 'vue'
- export const useUserStore = defineStore('user', () => {
- const username = ref('')
- function setUsername(name: string) {
- username.value = name
- }
- function clearUser() {
- username.value = ''
- }
- return { username, setUsername, clearUser }
- }, {
- persist: true // 开启持久化,自动存入 localStorage
- })
复制代码
开启后,username 变化时插件会自动写入 localStorage,页面刷新时自动读取恢复,Store 内不再需要手写 localStorage.setItem 和 localStorage.getItem。与方案一相比,方案二把持久化逻辑交给插件统一处理,更适合状态字段会持续增加的项目。
选择建议
当前只有 username 一个字段时,方案一只需改一行初始化代码,改动最小;如果后续还有 token、权限等更多状态需要持久化,方案二可以减少重复的手动读写代码,避免新增字段时漏掉初始化读取。两种方案都围绕同一个根因:Pinia 状态在内存中,刷新会重建,必须显式从 localStorage 恢复,或由持久化插件完成自动恢复。 |