真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Vue3狀態(tài)管理庫Pinia如何使用

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

成都創(chuàng)新互聯(lián)是一家專業(yè)提供安順企業(yè)網(wǎng)站建設(shè),專注與成都網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、H5場(chǎng)景定制、小程序制作等業(yè)務(wù)。10年已為安順眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。

什么是 Pinia

Pinia 與 Vuex 一樣,是作為 Vue 的“狀態(tài)存儲(chǔ)庫”,用來實(shí)現(xiàn) 跨頁面/組件形式的數(shù)據(jù)狀態(tài)共享。

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

Pinia 為何能取代 Vuex

作為 Vue 開發(fā)者都知道,Vuex 作為 Vue 的老牌官方狀態(tài)庫,已經(jīng)和 Vue 一起存在了很長(zhǎng)時(shí)間,為什么現(xiàn)在會(huì)被 Pinia 取代呢?

官方的說法主要是以下幾點(diǎn):

  • 取消 mutations。因?yàn)樵诖蟛糠珠_發(fā)者眼中,mutations 只支持 同步修改狀態(tài)數(shù)據(jù),而 actions雖然支持 異步,卻依然要在內(nèi)部調(diào)用 mutations 去修改狀態(tài),無疑是非常繁瑣和多余的

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

  • 不像 Vuex 一樣需要在實(shí)例/Vue原型上注入狀態(tài)依賴,而是通過直接引入狀態(tài)模塊、調(diào)用 getter/actions 函數(shù)來完成狀態(tài)的更新獲取;并且因?yàn)樽陨韺?duì) TypeScript 的良好支持和類型推斷,開發(fā)者可以享受很優(yōu)秀的代碼提示

  • 不需要預(yù)先注冊(cè)狀態(tài)數(shù)據(jù),默認(rèn)情況下都是根據(jù)代碼邏輯自動(dòng)處理的;并且可以在使用中隨時(shí)注冊(cè)新的狀態(tài)

  • 沒有 Vuex 的 modules 嵌套結(jié)構(gòu),所有狀態(tài)都是扁平化管理的。也可以理解為 pinia 注冊(cè)的狀態(tài)都類似 vuex 的 module,只是 pinia 不需要統(tǒng)一的入口來注冊(cè)所有狀態(tài)模塊

  • 雖然是扁平化的結(jié)構(gòu),但是依然支持 每個(gè)狀態(tài)之間的互相引用和嵌套

  • 不需要 namespace 命名空間,得利于扁平化結(jié)構(gòu),每個(gè)狀態(tài)在注冊(cè)時(shí)即使沒有聲明狀態(tài)模塊名稱,pinia 也會(huì)默認(rèn)對(duì)它進(jìn)行處理

總結(jié)一下就是:Pinia 在實(shí)現(xiàn) Vuex 全局狀態(tài)共享的功能前提下,改善了狀態(tài)存儲(chǔ)結(jié)構(gòu),優(yōu)化了使用方式,簡(jiǎn)化了 API 設(shè)計(jì)與規(guī)范;并且基于 TypeScript 的類型推斷,為開發(fā)者提供了良好的 TypeScript 支持與代碼提示。

如何使用

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

1. 注冊(cè) Pinia 實(shí)例

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

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

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

當(dāng)然,因?yàn)橹С?createApp 支持 鏈?zhǔn)秸{(diào)用,所以也可以直接寫成 createApp(App).use(createPinia()).mount('#app').

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

2. 定義狀態(tài) Store

在注冊(cè)一個(gè) Pinia 狀態(tài)模塊的時(shí)候,可以通過 defineStore方法創(chuàng)建一個(gè) 狀態(tài)模塊函數(shù)(之所以是函數(shù),是因?yàn)楹竺嬲{(diào)用的時(shí)候需要通過函數(shù)的形式獲取到里面的狀態(tài))。

deineStore 函數(shù)的 TypeScript 定義如下:

function defineStore(id, options): StoreDefinition
function defineStore(options): StoreDefinition
function defineStore(id, storeSetup, options?): StoreDefinition, _ExtractGettersFromSetupStore, _ExtractActionsFromSetupStore>

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

可以看到該函數(shù)最多接收 3個(gè)參數(shù),但是我們最常用的一般都是第一種或者第二種方式。這里以 第一種方式例,創(chuàng)建一個(gè)狀態(tài)模塊函數(shù):

// 該部分節(jié)選字我的開源項(xiàng)目 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) {
      this.editorSettings = { ...this.editorSettings, ...conf }
    }
  }
})

其中的 options配置項(xiàng)包含三個(gè)部分:

  • state:狀態(tài)的初始值,推薦使用的是一個(gè) 箭頭函數(shù),方便進(jìn)行類型推斷

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

  • actions:類似 Vue 中的 methods 配置項(xiàng),支持異步操作,主要作用是 處理業(yè)務(wù)邏輯并更新狀態(tài)數(shù)據(jù);另外,此時(shí)的 actions 是一個(gè) 函數(shù)集合對(duì)象,與 getters 不同的是 不建議使用箭頭函數(shù)。并且函數(shù)內(nèi)部的 this 就指向當(dāng)前 store 的 state。

注意:getters 的函數(shù)定義中 第一個(gè)參數(shù)就是當(dāng)前 store 的狀態(tài)數(shù)據(jù) state,而 actions 中的函數(shù)參數(shù)為 實(shí)際調(diào)用時(shí)傳遞的參數(shù),可以傳遞多個(gè),內(nèi)部通過 this 上下文直接訪問 state 并進(jìn)行更新。

3. 組件使用(配合 setup)

眾所周知,vue 3 最大的亮點(diǎn)之一就是 組合式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 狀態(tài)
    const { editorSettings } = storeToRefs(editor)
    
    // 使用 computed
    const editorSettings = computed(() => editor.editorSettings)

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

    return {
      editorStore
    }
  }
})

這里對(duì)以上幾種處理方式進(jìn)行說明:

獲取值:

  • 可以通過 解構(gòu)獲取 state 定義的數(shù)據(jù),但是 解構(gòu)會(huì)失去響應(yīng)式,所以需要用 storeToRefs重新對(duì)其進(jìn)行響應(yīng)式處理

  • 通過 computed計(jì)算屬性,好處是 可以對(duì) state 中的狀態(tài)數(shù)據(jù)進(jìn)行組合

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

更新值:

  1. 首先是可以 直接改變 state 的狀態(tài)值,缺點(diǎn)是多次使用容易有重復(fù)代碼,且不好維護(hù);也會(huì)影響代碼的可讀性

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

  3. $patch: 這個(gè)方式 可以接收一個(gè)對(duì)象或者函數(shù),但是 推薦使用箭頭函數(shù)(函數(shù)參數(shù)為狀態(tài)數(shù)據(jù) state);因?yàn)槿绻菍?duì)象,則需要根據(jù)新數(shù)據(jù)和當(dāng)前狀態(tài) 重建整個(gè) state,增加了很多的性能損耗;而使用箭頭函數(shù),其實(shí)就與 actions中的方式類似,可以 按代碼邏輯修改指定的狀態(tài)數(shù)據(jù)

4. 組件使用(沒有 setup)

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

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


mapStores 用來訪問 所有已注冊(cè) store 狀態(tài)。假設(shè)我們除了上文定義的 editor,還定義了一個(gè) 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 實(shí)例中訪問到。

5. 互相引用

因?yàn)?Pinia 本身是支持各個(gè) store 模塊互相引用的,所以在定義的時(shí)候可以直接引用其他 store 的數(shù)據(jù)進(jìn)行操作。

例如我們這里根據(jù) editor store 創(chuàng)建一個(gè) 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 模塊和組件使用

因?yàn)?Pinia 的每個(gè) store 模塊都是依賴 vue 應(yīng)用和 pinia 根實(shí)例的,在組件內(nèi)部使用時(shí)因?yàn)?Vue 應(yīng)用和 pinia 根實(shí)例肯定都已經(jīng)是 注冊(cè)完成處于活動(dòng)狀態(tài)中的,所以可以直接通過調(diào)用對(duì)應(yīng)的 store 狀態(tài)模塊函數(shù)即可。

但是在脫離 store 模塊與組件,直接在外部的純函數(shù)中使用時(shí),則需要注意 store 狀態(tài)模塊函數(shù)的調(diào)用時(shí)機(jī)。

以官方的示例來看:

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

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

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

router.beforeEach((to) => {
  // ? 這將起作用,因?yàn)槁酚善髟谥箝_始導(dǎo)航
   // 路由已安裝,pinia 也將安裝
  const store = useStore()

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

直接在js模塊的執(zhí)行中 直接調(diào)用是可能會(huì)報(bào)錯(cuò)的,因?yàn)榇藭r(shí)可能在 import router 的時(shí)候 還沒有調(diào)用 createApp 和 createPinia 創(chuàng)建對(duì)應(yīng)的應(yīng)用實(shí)例和 pinia 根實(shí)例,所以無法使用。

而在路由導(dǎo)航的攔截器中使用時(shí),因?yàn)?路由攔截觸發(fā)時(shí),應(yīng)用和 pinia 根實(shí)例肯定已經(jīng)全部實(shí)例化完畢,才可以正常使用。

所以 如果是在外部的 hooks 函數(shù)或者 utils 工具函數(shù)等純函數(shù)模塊中使用 store 數(shù)據(jù)時(shí),最好是定義一個(gè)函數(shù)方法導(dǎo)出,在組件或者 store 模塊中調(diào)用該方法,保證此時(shí)能正確執(zhí)行

到此,關(guān)于“Vue3狀態(tài)管理庫Pinia如何使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!


網(wǎng)站題目:Vue3狀態(tài)管理庫Pinia如何使用
URL網(wǎng)址:http://weahome.cn/article/jeiehe.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部