亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Vue3狀態管理庫Pinia如何使用

發布時間:2022-10-24 17:43:49 來源:億速云 閱讀:145 作者:iii 欄目:編程語言

這篇文章主要介紹“Vue3狀態管理庫Pinia如何使用”,在日常操作中,相信很多人在Vue3狀態管理庫Pinia如何使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Vue3狀態管理庫Pinia如何使用”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

什么是 Pinia

Pinia 與 Vuex 一樣,是作為 Vue 的“狀態存儲庫”,用來實現 跨頁面/組件 形式的數據狀態共享。

在平時的開發過程中,Vue 組件之間可以通過 PropsEvents 實現組件之間的消息傳遞,對于跨層級的組件也可以通過 EventBus 來實現通信。但是在大型項目中,通常需要在瀏覽器 保存多種數據和狀態,而使用 Props/Events 或者 EventBus 是很難維護和擴展的。所以才有了 Vuex 和 Pinia。

Pinia 為何能取代 Vuex

作為 Vue 開發者都知道,Vuex 作為 Vue 的老牌官方狀態庫,已經和 Vue 一起存在了很長時間,為什么現在會被 Pinia 取代呢?

官方的說法主要是以下幾點:

  • 取消 mutations。因為在大部分開發者眼中,mutations 只支持 同步修改狀態數據,而 actions 雖然支持 異步,卻依然要在內部調用 mutations 去修改狀態,無疑是非常繁瑣和多余的

  • 所有的代碼都是 TypeScript 編寫的,并且所有接口都盡可能的利用了 TypeScript 的 類型推斷,而不像 Vuex 一樣需要自定義 TS 的包裝器來實現對 TypeScript 的支持

  • 不像 Vuex 一樣需要在實例/Vue原型上注入狀態依賴,而是通過直接引入狀態模塊、調用 getter/actions 函數來完成狀態的更新獲取;并且因為自身對 TypeScript 的良好支持和類型推斷,開發者可以享受很優秀的代碼提示

  • 不需要預先注冊狀態數據,默認情況下都是根據代碼邏輯自動處理的;并且可以在使用中隨時注冊新的狀態

  • 沒有 Vuex 的 modules 嵌套結構,所有狀態都是扁平化管理的。也可以理解為 pinia 注冊的狀態都類似 vuex 的 module,只是 pinia 不需要統一的入口來注冊所有狀態模塊

  • 雖然是扁平化的結構,但是依然支持 每個狀態之間的互相引用和嵌套

  • 不需要 namespace 命名空間,得利于扁平化結構,每個狀態在注冊時即使沒有聲明狀態模塊名稱,pinia 也會默認對它進行處理

總結一下就是:Pinia 在實現 Vuex 全局狀態共享的功能前提下,改善了狀態存儲結構,優化了使用方式,簡化了 API 設計與規范;并且基于 TypeScript 的類型推斷,為開發者提供了良好的 TypeScript 支持與代碼提示。

如何使用

至于 Pinia 在項目中的安裝,大家應該都知道,直接通過包管理工具安裝即可。

1. 注冊 Pinia 實例

以 Vue 3 項目為例,只需要在入口文件 main.ts 中引入即可完成 Pinia 的注冊。

import { createApp } from 'vue'
import { createPinia } from 'pinia'

const app = createApp(App)
const pinia = createPinia()
app.use(pinia)

當然,因為支持 createApp 支持 鏈式調用,所以也可以直接寫成 createApp(App).use(createPinia()).mount('#app').

此時 createPinia() 創建的是一個根實例,在 app.use 的時候會在 app 中注入該實例,并且配置一個 app.config.globalProperties.$pinia 也指向該實例。

2. 定義狀態 Store

在注冊一個 Pinia 狀態模塊的時候,可以通過 defineStore 方法創建一個 狀態模塊函數(之所以是函數,是因為后面調用的時候需要通過函數的形式獲取到里面的狀態)。

deineStore 函數的 TypeScript 定義如下:

function defineStore<Id, S, G, A>(id, options): StoreDefinition<Id, S, G, A>
function defineStore<Id, S, G, A>(options): StoreDefinition<Id, S, G, A>
function defineStore<Id, SS>(id, storeSetup, options?): StoreDefinition<Id, _ExtractStateFromSetupStore<SS>, _ExtractGettersFromSetupStore<SS>, _ExtractActionsFromSetupStore<SS>>

type Id = ID extends string
type storeSetup = () => SS
type options = Omit<DefineStoreOptions<Id, S, G, A>, "id"> | DefineStoreOptions<Id, S, G, A> | DefineSetupStoreOptions<Id, _ExtractStateFromSetupStore<SS>, _ExtractGettersFromSetupStore<SS>, _ExtractActionsFromSetupStore<SS>>

可以看到該函數最多接收 3個參數,但是我們最常用的一般都是第一種或者第二種方式。這里以 第一種方式 例,創建一個狀態模塊函數:

// 該部分節選字我的開源項目 vite-vue-bpmn-process
import { defineStore } from 'pinia'
import { defaultSettings } from '@/config'
import { EditorSettings } from 'types/editor/settings'

const state = {
  editorSettings: defaultSettings
}

export default defineStore('editor', {
  state: () => state,
  getters: {
    getProcessDef: (state) => ({
      processName: state.editorSettings.processName,
      processId: state.editorSettings.processId
    }),
    getProcessEngine: (state) => state.editorSettings.processEngine,
    getEditorConfig: (state) => state.editorSettings
  },
  actions: {
    updateConfiguration(conf: Partial<EditorSettings>) {
      this.editorSettings = { ...this.editorSettings, ...conf }
    }
  }
})

其中的 options 配置項包含三個部分:

  • state:狀態的初始值,推薦使用的是一個 箭頭函數,方便進行類型推斷

  • getters:狀態的獲取,是一個對象格式;推薦配置為每個 getters 的對象屬性為 箭頭函數,方便進行類型推斷;在使用時等同于獲取該函數處理后的 state 狀態結果;并且與 Vue 的計算屬性一樣,該方法也是惰性的,具有緩存效果

  • actions:類似 Vue 中的 methods 配置項,支持異步操作,主要作用是 處理業務邏輯并更新狀態數據;另外,此時的 actions 是一個 函數集合對象,與 getters 不同的是 不建議使用箭頭函數并且函數內部的 this 就指向當前 store 的 state。

注意:getters 的函數定義中 第一個參數就是當前 store 的狀態數據 state,而 actions 中的函數參數為 實際調用時傳遞的參數,可以傳遞多個,內部通過 this 上下文 直接訪問 state 并進行更新。

3. 組件使用(配合 setup)

眾所周知,vue 3 最大的亮點之一就是 組合式API(Composition API),所以我們先以組件配合 setup 使用。

import { defineComponent, ref, computed } from 'vue'
import { storeToRefs } from 'pinia'
import { EditorSettings } from 'types/editor/settings'
import editorStore from '@/store/editor'

export default defineComponent({
  setup(props) {
    const editor = editorStore()
    
    // 直接獲取 state 狀態
    const { editorSettings } = storeToRefs(editor)
    
    // 使用 computed
    const editorSettings = computed(() => editor.editorSettings)

    // getters
    const prefix = editor.getProcessEngine
    
    // 更新方式 1:調用 actions
    editorStore.updateConfiguration({})
    
    // 更新方式 2:直接改變 state 的值
    editorStore.editorSettings = {}
    
    // 更新方式 3:調用 $patch
    editorStore.$patch((state) => {
      state.editorSettings = {}
    })

    return {
      editorStore
    }
  }
})

這里對以上幾種處理方式進行說明:

獲取值:

  • 可以通過 解構 獲取 state 定義的數據,但是 解構會失去響應式,所以需要用 storeToRefs 重新對其進行響應式處理

  • 通過 computed 計算屬性,好處是 可以對 state 中的狀態數據進行組合

  • 通過定義的 getters 方法來獲取值,這種方式獲取的結果本身就是 響應式的,可以直接使用

更新值:

  1. 首先是可以 直接改變 state 的狀態值,缺點是多次使用容易有重復代碼,且不好維護;也會影響代碼的可讀性

  2. 通過定義的 actions 更新,也算是推薦方法之一;在后續迭代和擴展中,只需要維護好 store 中的代碼即可

  3. $patch: 這個方式 可以接收一個對象或者函數,但是 推薦使用箭頭函數(函數參數為狀態數據 state);因為如果是對象,則需要根據新數據和當前狀態 重建整個 state,增加了很多的性能損耗;而使用箭頭函數,其實就與 actions 中的方式類似,可以 按代碼邏輯修改指定的狀態數據

4. 組件使用(沒有 setup)

而在傳統的 optionsAPI 模式的組件中(也沒有配置 setup),Pinia 也提供了與 Vuex 一致的 API:mapState,mapGetters,mapActions,另外還增加了 mapStores 用來訪問所有已注冊的 store 數據,新增了 mapWritableState 用來 定義可更新狀態;也因為 pinia 沒有 mutations,所以也取消了 mapMutations 的支持。

mapGetters 也只是為了方便遷移 Vuex 的組件代碼,后面依然建議 使用 mapState 替換 mapGetters

<template>
	<div>
    <p>{{ settings }}</p>
    <p>{{ processEngine }}</p>
    <button @click="updateConfiguration({})">調用 action</button>
    <button @click="update">調用 mapWritableState</button>
  </div>
</template>
<script>
  import { defineComponent, ref, storeToRefs } from 'vue'
  import { mapState, mapActions, mapWritableState } from 'pinia'
  import editorStore from '@/store/editor'
  
  export default defineComponent({
    computed: {
      ...mapState(editorStore, {
        settings: 'editorSettings',
        processEngine: (state) => `This process engine is ${state.editorSettings.processEngine}`
      }),
      ...mapWritableState(editorStore, ['editorSettings'])
    },
    methods: {
      ...mapActions(editorStore, ['updateConfiguration']),
      update() {
        this.editorSettings.processEngine = "xxx"
      }
    }
  })
</script>

mapStores 用來訪問 所有已注冊 store 狀態。假設我們除了上文定義的 editor,還定義了一個 id 為 modeler 的 store,則可以這么使用:

import editor from '@/store/editor'
import modeler from '@/store/modeler'
export default defineComponent({
  computed: {
    ...mapStores(editor, modeler)
  },
  methods: {
    async updateAll() {
      if (this.editorStore.processEngine === 'camunda') {
        await this.modelerStore.update()
      }
    }
  }
})

其中引用的所有 store,都可以通過 id + 'Store' 的形式在 Vue 實例中訪問到。

5. 互相引用

因為 Pinia 本身是支持各個 store 模塊互相引用的,所以在定義的時候可以直接引用其他 store 的數據進行操作。

例如我們這里根據 editor store 創建一個 modeler store

import { defineStore } from 'pinia'
import editor from '@/store/editor'

export default defineStore('editor', {
  state: () => ({
    element: null,
    modeler: null
  }),
  actions: {
    updateElement(element) {
      const editorStore = editor()
      if (!editorStore.getProcessEngine) {
        editorStore.updateConfiguration({ processEngine: 'camunda' })
      }
      this.element = element
    }
  }
})

6. 脫離 store 模塊和組件使用

因為 Pinia 的每個 store 模塊都是依賴 vue 應用和 pinia 根實例的,在組件內部使用時因為 Vue 應用和 pinia 根實例肯定都已經是 注冊完成處于活動狀態中的,所以可以直接通過調用對應的 store 狀態模塊函數即可。

但是在脫離 store 模塊與組件,直接在外部的純函數中使用時,則需要注意 store 狀態模塊函數的調用時機。

以官方的示例來看:

import { createRouter } from 'vue-router'
const router = createRouter({
  // ...
})

// ? 根據導入的順序,這將失敗
const store = useStore()

router.beforeEach((to, from, next) => {
  // 我們想在這里使用 store 
  if (store.isLoggedIn) next()
  else next('/login')
})

router.beforeEach((to) => {
  // ? 這將起作用,因為路由器在之后開始導航
   // 路由已安裝,pinia 也將安裝
  const store = useStore()

  if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})

直接在js模塊的執行中 直接調用是可能會報錯的,因為此時可能在 import router 的時候 還沒有調用 createApp 和 createPinia 創建對應的應用實例和 pinia 根實例,所以無法使用。

而在路由導航的攔截器中使用時,因為 路由攔截觸發時,應用和 pinia 根實例肯定已經全部實例化完畢,才可以正常使用。

所以 如果是在外部的 hooks 函數或者 utils 工具函數等純函數模塊中使用 store 數據時,最好是定義一個函數方法導出,在組件或者 store 模塊中調用該方法,保證此時能正確執行

到此,關于“Vue3狀態管理庫Pinia如何使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

毕节市| 右玉县| 融水| 天镇县| 军事| 祥云县| 济宁市| 高要市| 湖口县| 乐至县| 蛟河市| 绵阳市| 迁安市| 黄浦区| 平南县| 西贡区| 大同县| 舒兰市| 永安市| 屯昌县| 聂拉木县| 芮城县| 河北区| 安吉县| 广德县| 方城县| 泰顺县| 花莲市| 合阳县| 岳阳县| 社旗县| 积石山| 永新县| 托克托县| 印江| 大足县| 长泰县| 江川县| 灌云县| 四川省| 德令哈市|