在Vue3項目中使用pinia代替Vuex進行數據存儲

来源:https://www.cnblogs.com/wuhuacong/archive/2022/04/08/16117968.html
-Advertisement-
Play Games

pinia是一個vue的狀態存儲庫,你可以使用它來存儲、共用一些跨組件或者頁面的數據,使用起來和vuex非常類似。pina相對Vuex來說,更好的ts支持和代碼自動補全功能。本篇隨筆介紹pinia的基礎用法以及持久化存儲的一些用法,供參考學習。 pinia在2019年11月開始時候是一個實驗項目,目... ...


pinia是一個vue的狀態存儲庫,你可以使用它來存儲、共用一些跨組件或者頁面的數據,使用起來和vuex非常類似。pina相對Vuex來說,更好的ts支持和代碼自動補全功能。本篇隨筆介紹pinia的基礎用法以及持久化存儲的一些用法,供參考學習。

pinia在2019年11月開始時候是一個實驗項目,目的就是重新設計一個與組合API匹配的vue狀態存儲。基本原則和原來還是一樣的,pinia同時支持vue2和vue3,且不要求你必須使用Vue3的組合API。不管是使用vue2或者vue3,pinia的API是相同的,文檔是基於vue3寫的。

Pinia 是 Vuex4 的升級版,也就是 Vuex5; Pinia 極大的簡化了Vuex的使用,是 Vue3的新的狀態管理工具;Pinia 對 ts的支持更好,性能更優, 體積更小,無 mutations,可用於 Vue2 和 Vue3;Pinia支持Vue Devtools、 模塊熱更新和服務端渲染。

1、pinia的安裝和使用

安裝pinia(https://pinia.vuejs.org/)

npm install pinia

在main.j或者main.ts中引入使用

import { createPinia } from 'pinia'

app.use(createPinia())

下麵就是使用pinia的一個例子。這樣你就創建了一個狀態存儲。

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => {
    return { count: 0 }
  },
  // 也可以這樣定義狀態
  // state: () => ({ count: 0 })
  actions: {
    increment() {
      this.count++
    },
  },
})

在組件中使用:

import { useCounterStore } from '@/stores/counter'

export default {
  setup() {
    const counter = useCounterStore()

    counter.count++
    // 編輯器會有代碼提示 
    counter.$patch({ count: counter.count + 1 })
    // 也可以使用action來代替
    counter.increment()
  },
}
如果你不是很喜歡setup函數和組合API,pinia也有類似vuex的map的功能。你可以用上面的方式定義你的store,但是使用時用mapStores(), mapState(),或者 mapActions():
const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

const useUserStore = defineStore('user', {
  // ...
})

export default {
  computed: {
    // 其他計算屬性
    // ...
    // 可以使用 this.counterStore 和 this.userStore獲取
    ...mapStores(useCounterStore, useUserStore)
    // 可以使用 this.count 和this.double獲取
    ...mapState(useCounterStore, ['count', 'double']),
  },
  methods: {
    // 可以使用 this.increment()調用
    ...mapActions(useCounterStore, ['increment']),
  },
}

與vue4之前的版本相比,pinia的API是有很多不同的,即:

  • 去掉了mutation。因為好多人認為mutation是多餘的。以前它方便devtools集成,現在這不是個問題了。
  • 不用在寫複雜的ts類型包裝,所有的都是有類型的,API設計的都是儘量符合ts的類型推斷
  • 不再使用一個莫名其妙的字元串了,只需要導入一個函數,調用他們就行了,同時還有代碼自動補全
  • 不需要動態添加store了,因為它們現在本來就是動態。如果你想,你隨時可以手動去寫一個store。
  • 沒有複雜的嵌套模塊了。你仍然可以在一個store中導入其他的store來實現嵌套模塊,但是pinia還是推薦使用一個扁平的結構。但是即使你使用迴圈依賴也沒關係。
  • 不再需要命名空間了。因為現在store本來就是扁平結構了。你也可以理解為所有的store本來就有命名空間了。
你的應用中的全局數據需要保存在store中。在很多地方你都要使用這些數據,比如說,用戶信息需要在導航欄中顯示,也需要在個人中心顯示。還有些數據,需要暫存起來,比如一個需要分好幾頁填寫的表單。 在pinia中,store是通過defineStore()方法定義的,它的第一個參數就是一個唯一的名字:
import { defineStore } from 'pinia'

export const useStore = defineStore('main', {
  // other options...
})

上面只是定義了store,在setup函數中調用了useStore()時,才會創建store:

import { useStore } from '@/stores/counter'

export default {
  setup() {
    const store = useStore()

    return {
      // 你可以返回store這個對象,然後就可以在template中使用了
      store,
    }
  },
}

在store實例化以後,你就可以調用到store中定義的state、getters和actions了。為了讓解構的值還保持響應式,你需要用到storeToRefs()方法。它會給響應式的數據創建ref。

import { storeToRefs } from 'pinia'

export default defineComponent({
  setup() {
    const store = useStore()
    // `name` 和 `doubleCount` 是響應式的
    // 插件增加的屬性也會創建ref
    // 但是會自動跳過action或者不是響應性的屬性
    const { name, doubleCount } = storeToRefs(store)

    return {
      name,
      doubleCount
    }
  },
})

預設情況下,你可以在store實例上直接獲取或者修改state:

const store = useStore()
store.counter++

也可以調用$reset()方法來把state恢復為初始值:

const store = useStore()
store.$reset()

除了直接修改store里的值store.counter++,你也可以是用$patch方法。你可以同時修改多個值:

store.$patch({
  counter: store.counter + 1,
  name: 'Abalam',
})

或者$patch接收一個函數作為參數,來簡化改變數組的寫法:

store.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

 

2、pinia的持久化存儲處理

你可以用$subscribe()來偵聽state的改變,持久化一般存儲在localStorage和sessionStorage。

localStorage和sessionStorage差別

localStorage和sessionStorage一樣都是用來存儲客戶端臨時信息的對象。

他們均只能存儲字元串類型的對象(雖然規範中可以存儲其他原生類型的對象,但是目前為止沒有瀏覽器對其進行實現)。

localStorage生命周期是永久,這意味著除非用戶顯示在瀏覽器提供的UI上清除localStorage信息,否則這些信息將永遠存在。

sessionStorage生命周期為當前視窗或標簽頁,一旦視窗或標簽頁被永久關閉了,那麼所有通過sessionStorage存儲的數據也就被清空了。

不同瀏覽器無法共用localStorage或sessionStorage中的信息。相同瀏覽器的不同頁面間可以共用相同的 localStorage(頁面屬於相同功能變數名稱和埠),但是不同頁面或標簽頁間無法共用sessionStorage的信息。這裡需要註意的是,頁面及標 簽頁僅指頂級視窗,如果一個標簽頁包含多個iframe標簽且他們屬於同源頁面,那麼他們之間是可以共用sessionStorage的。

JSON對象提供的parse和stringify將其他數據類型轉化成字元串,再存儲到storage中就可以了,操作的方式:

存:

var obj = {"name":"xiaoming","age":"16"}

localStorage.setItem("userInfo",JSON.stringify(obj));

取:

var user = JSON.parse(localStorage.getItem("userInfo"))

刪除:

localStorage.remove("userInfo);

清空:

localStorage.clear();

 

pnia 使用訂閱機制subscribe來實現數據的持久化存儲的代碼如下所示。

const instance = useMainStore();
// 訂閱數據變化,變化時存儲 instance.$id 這是storeId
instance.$subscribe((mutation, state) => {
  localStorage.setItem(instance.$id, JSON.stringify(state));
});

//init 初始的時候獲取
const val = localStorage.getItem(instance.$id);
if (val) {
  instance.$state = JSON.parse(val);
}

也可以通過watch實現

watch(
  pinia.state,
  (state) => {
    // persist the whole state to the local storage whenever it changes
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

但是需要註意,這種方式持久化會提示pinia未安裝掛載,所以需要在pinia掛載後再調用,這裡可以將它封裝成方法導出,在掛載後調用

xport const initStore = () => {
  const instance = useMainStore();
  // 訂閱數據變化,變化時存儲 instance.$id 這是storeId
  instance.$subscribe((mutation, state) => {
    localStorage.setItem(instance.$id, JSON.stringify(state));
  });

  //init 初始的時候獲取
  const val = localStorage.getItem(instance.$id);
  if (val) {
    instance.$state = JSON.parse(val);
  }

}
預設情況下,state偵聽會和組件綁定在一起(如果store是在組件的setup中)。這意味著,當組件卸載時,偵聽會自動被移除。如果你需要在組件被卸載時,偵聽仍然保持,需要給$subscribe()方法傳遞第二個參數true:
export default {
  setup() {
    const someStore = useSomeStore()

    // 組件卸載後,偵聽也會有
    someStore.$subscribe(callback, true)

    // ...
  },
}

或者watch狀態的變化

watch(
  pinia.state,
  (state) => {
    // 在state改變時,保存在localStorage中
    localStorage.setItem('piniaState', JSON.stringify(state))
  },
  { deep: true }
)

 

3、使用pinia插件持久化存儲

pinia plugin persist官方網站:pinia-plugin-persist

持久化存儲也可以通過安裝插件的方式,安裝 pinia-plugin-persist 來實現。

npm i pinia-plugin-persist --save

使用main.js

import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
store.use(piniaPluginPersist)
createApp(App).use(store).mount('#app')

在對應的store中開啟,數據預設存在 sessionStorage 里,並且會以 storeId 作為 key

import { defineStore } from 'pinia'
// 'main' 是storeId
export const useMainStore = defineStore('main', {
  state: () => ({
    counter: 2,
    name: 'Eduardo',
    isAdmin: true
  }),
  // ……
  // 開啟數據緩存
  persist: {
    enabled: true
  }
})

如果需要自定義key和存儲位置,則修改參數即可。

  persist: {
    enabled: true,
    strategies: [ //使用插件自定義存儲
      {
        key: 'settings', // key可以自己定義,不填的話預設就是這個store的ID
        storage: localStorage, 
      }
    ]
  },

 

 4、在實際項目中使用pinia

一般項目開發,實際上存儲的內容會比較多,可能根據不同的鍵值模塊進行區分,因此把它們放在一個store/modules裡面,方便的使用引用它來存取設置數據即可。

我們這裡簡單以一個settings的配置信息進行介紹,其中index.ts是一個統一的創建pinia的對象並掛接到全局App上的。

其中index.ts的代碼如下所示。

import type { App } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersist from 'pinia-plugin-persist';//使用插件持久化

const store = createPinia();
store.use(piniaPluginPersist) //使用插件持久化

export function setupStore(app: App<Element>) {
  app.use(store);
}

export { store };

因此在main.js裡面引入並掛接pinia即可。

import { createApp } from 'vue'

import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import 'normalize.css' // css初始化

import App from './App.vue'
import { setupStore } from "/@/store";

const app = createApp(App)
setupStore(app)
app.use(ElementPlus)
app.mount('#app')

這樣我們就可以再次定義一個模塊化的配置信息,以便於管理存儲各種不同類型的內容。

如下麵我們定義一個程式配置信息setttings.ts

import { defineStore } from "pinia";
import { store } from "/@/store";

export type settingType = {
    title: string;
    fixedHeader: boolean;
    hiddenSideBar: boolean;
  };

export const useSettingStore = defineStore({
  id: "settings",
  state: (): settingType => ({
    title: "Vue3 + TypeScript + Element",
    fixedHeader: false,
    hiddenSideBar: false
  }),
  persist: {
    enabled: true,
    strategies: [ //使用插件自定義存儲
      {
        key: 'settings', // key可以自己定義,不填的話預設就是這個store的ID
        storage: localStorage, 
      }
    ]
  },

  getters: {
    getTitle() {
      return this.title;
    },
    getFixedHeader() {
      return this.fixedHeader;
    },
    getHiddenSideBar() {
      return this.HiddenSideBar;
    }
  },
  actions: {
    CHANGE_SETTING({ key, value }) {
      // eslint-disable-next-line no-prototype-builtins
      if (this.hasOwnProperty(key)) {
        this[key] = value;
      }
    },
    changeSetting(data) {
      this.CHANGE_SETTING(data);
    }
  }
});

export function useSettingStoreHook() {
  return useSettingStore(store);
}

然後在組件視圖vue或者app.vue中使用即可

<script lang="ts">
import { defineComponent } from "vue";

import { useSettingStoreHook } from "/@/store/modules/settings";
import { storeToRefs } from "pinia";

export default defineComponent({
  name: "app",
  components: {
  },
  setup() {
    const store = useSettingStoreHook();

    const { fixedHeader, title } = storeToRefs(store);
    return {
      fixedHeader,
      title,
    };
  },
  methods: {
    setTitle() {
      this.title = "Vue3 + TypeScript + Element + Edit";
      console.log(this.title);
    },
  },
});
</script>

查看數據修改後,存儲在本地存儲空間中的內容,如下所示。

 

 

 

 

 

主要研究技術:代碼生成工具、會員管理系統、客戶關係管理軟體、病人資料管理軟體、Visio二次開發、酒店管理系統、倉庫管理系統等共用軟體開發
專註於Winform開發框架/混合式開發框架Web開發框架Bootstrap開發框架微信門戶開發框架的研究及應用
  轉載請註明出處:
撰寫人:伍華聰  http://www.iqidi.com 
    

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 CentOS8 AnolisOS8 yum安裝失敗 今天有人反饋伺服器卡,登錄上伺服器,想看下CPU以及記憶體使用情況,覺得top看不太清晰,想使用htop,發現沒有,就想安裝一個htop,輸入命令,yum安裝 yum install htop 沒 ...
  • 互聯網發展至今,實時視頻和語音通話越來越被大眾所依賴。 今天,我們將會繼續介紹如何基於ZEGO SDK實現音視頻通話功能,前兩篇文章分別介紹了Android,Flutter平臺的實現方式,感興趣的小伙伴可點擊瞭解: [Android](https://zegoguanwang.datasink.s... ...
  • 鏡像下載、功能變數名稱解析、時間同步請點擊 阿裡雲開源鏡像站 一、OceanBase介紹 OceanBase是由螞蟻集團完全自主研發的金融級分散式關係資料庫,始創於2010年。OceanBase具有數據強一致、高可用、高性能、線上擴展、高度相容SQL標準和主流關係資料庫、低成本等特點。 OceanBase ...
  • MySQL8.0.x 安裝 一、下載 MySQL官網下載鏈接:https://downloads.mysql.com/archives/community/ 選擇版本後下載zip文件 博主選擇的是8.0.13 二、安裝 1 解壓 把下載好的zip包在你想要的路徑下直接解壓。 解壓完成後得到這個界面: ...
  • cluster概念澄清 postgresql中沒有聚集索引的概念,表都是以堆(heap)的方式存在,可以認為數據在物理存儲上是無序的。cluster:這裡的cluster不是指多個機器的組成的集群,而是指表中數據行按照某種方式物理排序存儲。是一種改變postgresql表的物理存儲的一種方案。適應場 ...
  • 在鴻蒙開發中tab切換功能(如下圖所示)是非常常見一個功能,今天描述如下功能怎麼實現?開發中需要準備哪些資料? 今天我們從“資料準備”,“Tabs功能實現”,“底部按鈕功能實現”,“運行效果”四個方面進行描述 1. 開發準備 1.1 資料準備 想要實現如上圖功能的話,需要學習“Tabs”,“TabC ...
  • 背景 開發者在應用中集成HMS Core部分服務時,android sdk 以及flutter等跨平臺sdk,會出現編譯打包後,運行報6003錯誤碼的情況。根據查詢可以得知,錯誤代碼 6003 表示證書指紋配置不一致,主要是生成的包(例如安卓apk)的簽名,與華為開發者平臺上應用設置裡面配置的不一致 ...
  • 即時通訊(Instant Messaging)是一種基於互聯網的即時交流消息的業務。 實時聊天交互功能是市面上主流APP的重要功能之一,人們所熟悉的就是微信,QQ的聊天消息系統,IM看似簡單,技術開發絕非易事,海量併發,超低延時,消息必達等高實時性需求需要眾多技術的應用合體; IM結合RTC可以... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...