寫個庫,讓 Vue3 Pinia 持久化,且存儲容量大大提升!
前言
大家好,我是林三心,用最通俗易懂的話講最難的知識點是我的座右銘,基礎是進階的前提是我的初心~
背景
我們平時使用 Vue3 開發項目的時候,要考慮的一個問題就是,有一些數據需要項目各個地方去用到,所以我們會用到全局狀態管理工具,比較常用的是Vuex、Pinia
,不過 Vue3 中用的比較多的應該是 Pinia
了
有一些場景我們需要用戶刷新頁面之後,Pinia
中的數據能還原,這樣能減少請求的次數,優化用戶體驗,這就涉及到了 Pinia持久化
問題
pinia-plugin-persistedstate
其實市面上已經有提供 Pinia 持久化的庫了,那就是pinia-plugin-persistedstate
這個庫,他讓Pinia
具備了刷新後還原的能力
但是我發現這個庫有兩個不足的點:
-
不支持配置前綴後綴
-
不支持自定義存儲方式
前綴後綴
爲什麼需要前綴後綴呢?我們想想,如果一個域名下有兩個子項目的話,那我們怎麼去防止他們兩個的持久化數據互相污染呢?比較普遍的方式就是給每個項目持久化數據的 key 增加前綴或後綴
自定義存儲方式
目前這個庫只支持 storage 存儲,但是我們都只到 storage 的存儲大小爲 5M,如果數據量超過,就會引起報錯,影響頁面的整體邏輯,所以我覺得需要可配置存儲方式,支持 indexedDB、storage
pinia-plugin-persistedstore
所以我開發了一個庫 pinia-plugin-persistedstore
,他是基於pinia-plugin-persistedstate
去二次開發的~
拓展 & 改動 & 無縫切換
我拓展了兩個功能:
-
支持配置前綴後綴
-
支持可配置存儲方式
改變了幾個功能:
-
去除了 serializer 配置,改爲在內部自己轉換
-
persist 不支持傳數組,只能傳一個配置
-
暫時沒兼容 SSR
開發這個庫,還要保證一個點:使用起來跟 pinia-plugin-persistedstate 基本一樣,這樣開發者才能無縫切換~
原理
其實源碼很少,分爲幾步:
-
1、接收
Pinia
實例 -
2、獲取實例上的
store
實例 -
3、在
store.$subscribe
中,對數據進行持久化存儲 -
4、初始化時獲取持久化數據,調用
store.$patch
進行還原
簡單的僞代碼代碼結構如下,如果想看完整源碼可以看:
-
github: https://github.com/sanxin-lin/pinia-persist/tree/main
-
npm: https://www.npmjs.com/package/pinia-plugin-persistedstore
// plugin.ts
export const plugin = (context: PiniaPluginContext) => {
const { store } = context;
// 初始化時拿數據,進行還原
const data = storage.getItem(key)
store.$patch(data);
// 數據變了就存儲
store.$subscribe(
(_mutation: SubscriptionCallbackMutation<StateTree>, state: StateTree) => {
// 持久化存儲
persistState(state, _persist);
},
{
detached: true,
},
);
};
// 插件使用
import { createPinia } from 'pinia';
import plugin from './plugin,ts';
const store = createPinia();
store.use(plugin);
特點
-
✅
pinia
的持久化 -
✅ 各個模塊支持自定義持久化配置
-
✅ 支持
indexedDB、storage
進行存儲,解決容量大小問題 -
✅ 支持通過配置
前綴、後綴
,防止子項目之間持久化數據互相污染
安裝
// npm
npm i pinia-plugin-persistedstore
// yarn
yarn add pinia-plugin-persistedstore
// pnpm
pnpm i pinia-plugin-persistedstore
使用
初始化
// 直接配置插件
import { createPinia } from 'pinia'
import piniaPluginPersistedStore from 'pinia-plugin-persistedstore'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
如果你不想要同域名下子項目持久化數據之間互相污染,可以配置前綴或後綴
// 爲緩存添加前綴後綴
import { createPlugin } from 'pinia-plugin-persistedstore';
const store = createPinia();
const store = createPinia();
store.use(
createPlugin({
prefix: 'sunshine_prefix',
suffix: 'sunshine_suffix',
}),
);
模塊配置
模塊想要啓用持久化,可以配置 persist
參數,它的類型是 TPersist
export interface IBasePersist {
// 持久化存儲的key(可選)
key?: string;
// 需要持久化的數據的路徑(可選)
paths?: string[];
// 還原前執行函數(可選)
beforeRestore?: (context: PiniaPluginContext) => void;
// 還原後執行函數(可選)
afterRestore?: (context: PiniaPluginContext) => void;
// 還原失敗打印報錯(可選)
debug?: boolean;
}
export interface IPersist extends IBasePersist {
// storage類型,有localStorage、sessionStroage(可選)
storage?: Storage;
// 使用 indexedDB 或 storage(可選)
type?: 'storage' | 'db';
}
// persist 的類型
export type TPersist = boolean | IPersist;
當你要啓用持久化時,可以這麼做
export const useUserStore = defineStore({
id: 'app-user',
persist: true, // 開啓持久化
state: (): UserState => ({
name: 'sunshine'
})
});
當你設置 persist = true
時,此模塊開啓了持久化功能,相當於傳入了
persist: {
storage: localStorage,
type: 'storage',
key: $store.id, // 此模塊的默認id
paths: null,
beforeRestore: null,
afterRestore: null,
debug: false,
}
當然你也可以自己去進行配置,比如以下例子
export const useUserStore = defineStore({
id: 'app-user',
persist: {
type: 'db',
key: 'user_key',
paths: ['userInfo', 'token'],
beforeRestore: () => {
console.log('beforeRestore');
},
afterRestore: () => {
console.log('afterRestore');
},
debug: true,
},
state: (): UserState => ({
userInfo: null,
token: undefined,
roleList: [],
}),
});
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/z4SxH4-o0dhzsrWREmVANg