寫個庫,讓 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去二次開發的~

拓展 & 改動 & 無縫切換

我拓展了兩個功能:

改變了幾個功能:

開發這個庫,還要保證一個點:使用起來跟 pinia-plugin-persistedstate 基本一樣,這樣開發者才能無縫切換~

原理

其實源碼很少,分爲幾步:

簡單的僞代碼代碼結構如下,如果想看完整源碼可以看:

// 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);

特點

安裝

// 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