Appearance
Pinia 状态持久化
Pinia 本身不提供状态持久化功能,但可以通过插件或自定义实现来将状态保存到本地存储中。本指南将详细介绍如何实现 Pinia 状态的持久化。
使用 pinia-plugin-persistedstate 插件
这是最常用的持久化解决方案。
安装插件
bash
npm install pinia-plugin-persistedstate
基本配置
javascript
// main.js 或 main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.mount('#app')
在 Store 中启用持久化
javascript
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
email: '',
preferences: {
theme: 'light',
language: 'en',
},
}),
// 启用持久化
persist: true, // 简单持久化,使用默认设置
})
高级持久化配置
javascript
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
email: '',
preferences: {
theme: 'light',
language: 'en',
},
loginCount: 0,
}),
persist: {
// 自定义存储键名
key: 'user-store',
// 选择要持久化的状态字段
pick: ['name', 'preferences'], // 只持久化 name 和 preferences 字段
// 排除某些字段不持久化
// omit: ['loginCount'], // 不持久化 loginCount 字段
// 自定义存储方式
storage: localStorage, // 默认为 localStorage
// 自定义序列化函数
serializer: {
serialize: JSON.stringify,
deserialize: JSON.parse,
},
},
})
多存储支持
使用 sessionStorage
javascript
export const useTempStore = defineStore('temp', {
state: () => ({
temporaryData: null,
sessionInfo: {},
}),
persist: {
storage: sessionStorage, // 使用 sessionStorage,页面关闭后数据丢失
},
})
自定义存储实现
javascript
// 自定义存储适配器
const customStorage = {
getItem(key) {
// 自定义获取逻辑
return localStorage.getItem(key)
},
setItem(key, value) {
// 自定义设置逻辑
localStorage.setItem(key, value)
},
removeItem(key) {
// 自定义删除逻辑
localStorage.removeItem(key)
},
}
export const useCustomStore = defineStore('custom', {
state: () => ({
data: {},
}),
persist: {
storage: customStorage,
},
})
复杂持久化场景
分割持久化配置
javascript
export const useAppStore = defineStore('app', {
state: () => ({
user: null,
settings: {
theme: 'light',
notifications: true,
},
cache: {},
tempData: null,
}),
persist: [
{
// 用户信息使用 localStorage 持久化
key: 'app-user',
pick: ['user'],
storage: localStorage,
},
{
// 设置使用 sessionStorage 持久化
key: 'app-settings',
pick: ['settings'],
storage: sessionStorage,
},
{
// 缓存数据使用自定义存储
key: 'app-cache',
pick: ['cache'],
storage: localStorage,
},
],
})
条件持久化
javascript
export const useConditionalStore = defineStore('conditional', {
state: () => ({
sensitiveData: null,
publicData: {},
userPreferences: {},
}),
persist: computed(() => {
const shouldPersist = localStorage.getItem('enablePersistence') === 'true'
if (shouldPersist) {
return {
pick: ['publicData', 'userPreferences'],
storage: localStorage,
}
} else {
return false // 不启用持久化
}
}),
})
手动持久化实现
如果不使用插件,可以手动实现持久化:
javascript
import { defineStore } from 'pinia'
export const useManualPersistStore = defineStore('manual-persist', {
state: () => ({
count: 0,
name: '',
lastUpdated: null,
}),
actions: {
// 初始化时从存储加载数据
hydrate() {
const savedState = localStorage.getItem('manual-persist-store')
if (savedState) {
const parsedState = JSON.parse(savedState)
this.$patch(parsedState)
}
},
// 手动保存到存储
saveToStorage() {
const stateToSave = {
count: this.count,
name: this.name,
lastUpdated: this.lastUpdated,
}
localStorage.setItem('manual-persist-store', JSON.stringify(stateToSave))
},
increment() {
this.count++
this.lastUpdated = new Date().toISOString()
this.saveToStorage() // 每次修改后保存
},
setName(newName) {
this.name = newName
this.lastUpdated = new Date().toISOString()
this.saveToStorage()
},
},
// 在 Store 初始化后自动加载数据
hydrate: {
afterHydrate: () => {
// 可以在这里添加加载后的回调逻辑
},
},
})
// 在组件挂载时调用 hydrate
// onMounted(() => {
// const store = useManualPersistStore()
// store.hydrate()
// })
数据迁移和版本控制
带版本控制的持久化
javascript
export const useVersionedStore = defineStore('versioned', {
state: () => ({
version: 1,
data: {},
settings: {},
}),
persist: {
key: 'versioned-store-v1', // 在键名中包含版本号
serializer: {
serialize: (state) => {
// 在序列化时添加元数据
return JSON.stringify({
version: state.version,
timestamp: Date.now(),
data: state,
})
},
deserialize: (value) => {
try {
const parsed = JSON.parse(value)
// 如果版本不匹配,执行迁移逻辑
if (parsed.version !== 1) {
return migrateData(parsed)
}
return parsed.data
} catch (error) {
console.error('Failed to deserialize persisted state:', error)
return { version: 1, data: {}, settings: {} }
}
},
},
},
})
function migrateData(oldData) {
// 执行数据迁移逻辑
const newData = { ...oldData }
// 根据需要执行迁移操作
newData.version = 1
return newData
}
性能优化
防抖持久化
javascript
import { debounce } from 'lodash-es' // 或使用自己的防抖函数
export const useDebouncedStore = defineStore('debounced', {
state: () => ({
input: '',
searchHistory: [],
}),
actions: {
// 防抖保存函数
saveToStorage: debounce(function() {
const stateToSave = {
input: this.input,
searchHistory: this.searchHistory,
}
localStorage.setItem('debounced-store', JSON.stringify(stateToSave))
}, 500), // 500ms 防抖
updateInput(newInput) {
this.input = newInput
this.saveToStorage() // 触发防抖保存
},
},
})
选择性持久化
javascript
export const useSelectiveStore = defineStore('selective', {
state: () => ({
largeData: new Array(10000).fill(0).map((_, i) => i),
smallData: { count: 0 },
uiState: { expanded: false },
}),
persist: {
// 只持久化小数据和 UI 状态,避免持久化大数据
pick: ['smallData', 'uiState'],
},
})
安全考虑
敏感数据处理
javascript
export const useSecureStore = defineStore('secure', {
state: () => ({
token: null,
refreshToken: null,
sensitiveInfo: null,
publicInfo: {},
}),
persist: {
// 只持久化非敏感数据
pick: ['publicInfo'],
},
actions: {
// 敏感数据手动处理
setTokens(token, refreshToken) {
this.token = token
this.refreshToken = refreshToken
// 不持久化敏感数据,但可以临时存储在内存中
},
},
})
调试和监控
持久化监控
javascript
const persistenceLogger = (context) => {
const { store } = context
// 监听持久化事件
store.$subscribe((mutation, state) => {
console.log(`Store ${store.$id} persisted:`, mutation, state)
}, { detached: true })
}
// 使用插件
pinia.use(persistenceLogger)
通过以上方法,您可以根据应用需求选择合适的持久化策略,确保用户数据在页面刷新或应用重启后得以保留。