Heim  >  Artikel  >  Web-Frontend  >  Ausführliche Erklärung zur Verwendung der Vue3-Staatsverwaltungsbibliothek Pinia

Ausführliche Erklärung zur Verwendung der Vue3-Staatsverwaltungsbibliothek Pinia

青灯夜游
青灯夜游nach vorne
2022-10-20 19:29:242916Durchsuche

Was ist Pinia? Wie benutzt man? In diesem Artikel erfahren Sie mehr über die State-Management-Bibliothek der neuen Generation – Pinia. Ich hoffe, dass er Ihnen weiterhilft!

Ausführliche Erklärung zur Verwendung der Vue3-Staatsverwaltungsbibliothek Pinia

Nachdem die offizielle Version von Vue 3 im September 2020 veröffentlicht wurde, veröffentlichte Vuex im Februar 2021 auch die an Vue 3 angepasste Version 4.0. Ende August 2021 wurde sie jedoch hauptsächlich von Eduardo beigesteuert, ein Mitglied des Vue-Kernteams. Die neue Vue State Shared Library veröffentlichte Version 2.0, und im November desselben Jahres ernannte Youda Pinia offiziell zur offiziellen State Library von Vue (jetzt hat die offizielle Vue-Website Vuex durch Pinia ersetzt). ). (Teilen von Lernvideos: vue-Video-Tutorial)

Was ist Pinia? Pinia ist wie Vuex ein „Status-Repository

“ für Vue, das zur Implementierung einer seiten-/komponentenübergreifenden Form des Datenstatus verwendet wird geteilt.

Im normalen Entwicklungsprozess können Vue-Komponenten über Props und Events

miteinander kommunizieren. Bei ebenenübergreifenden Komponenten kann die Kommunikation auch über

EventBus erreicht werden. Bei großen Projekten ist es jedoch meist notwendig, mehrere Daten und Zustände im Browser zu speichern und die Verwendung von Props/Events oder EventBus ist schwierig zu warten und zu erweitern. Daher Vuex und Pinia. Warum kann Pinia Vuex ersetzen? Als Vue-Entwickler wissen wir alle, dass Vuex als alte offizielle Staatsbibliothek von Vue schon lange mit Vue existiert. Warum wird es jetzt durch Pinia ersetzt? Die offizielle Aussage lautet im Wesentlichen wie folgt:

Abbrechen Mutationen

. Denn in den Augen der meisten Entwickler unterstützen Mutationen nur die

synchrone Änderung von Statusdaten

, und obwohl

Aktionen

die
    asynchrone
  • unterstützen, müssen sie dennoch Mutationen intern aufrufen, um den Status zu ändern, was zweifellos sehr umständlich und überflüssig ist

    Alle Codes sind in TypeScript geschrieben und alle Schnittstellen nutzen vollständig die Typinferenz von TypeScript, im Gegensatz zu Vuex, das einen benutzerdefinierten TS-Wrapper zur Unterstützung von TypeScript erfordert.

  • Vuex muss auch Zustandsabhängigkeiten in die Instanz/Vue einfügen Prototyp, führt jedoch direkt das Statusmodul ein und ruft die Getter-/Aktionsfunktion auf, um die Statusaktualisierungserfassung abzuschließen. Aufgrund der guten Unterstützung für TypeScript und Typinferenz können Entwickler sehr hervorragende Codetipps genießen. Dies ist nicht erforderlich Statusdaten vorab registrieren
  • , standardmäßig werden sie automatisch gemäß der Codelogik verarbeitet; und neuer Status kann jederzeit während der Verwendung registriert werden

  • Keine Vuex-Module eingebettet. Festgelegte Struktur, alle Zustände werden flach verwaltet
  • . Es kann auch verstanden werden, dass der von Pinia registrierte Status dem Modul von Vuex ähnelt, mit der Ausnahme, dass Pinia keinen einheitlichen Eingang benötigt, um alle Statusmodule zu registrieren

    Obwohl es sich um eine flache Struktur handelt, unterstützt es dennoch gegenseitige Referenzen zwischen Jeder Status und jede Verschachtelung
  • erfordert keinen Namensraum und profitiert von einer flachen Struktur. Auch wenn jeder Status bei der Registrierung keinen Statusmodulnamen deklariert, verarbeitet Pinia ihn standardmäßig

  • Zusammenfassend: Unter der Prämisse, die Funktion der globalen Statusfreigabe von Vuex zu realisieren, verbessert Pinia die Statusspeicherstruktur, optimiert die Nutzung, vereinfacht das API-Design und die Spezifikation und bietet Entwicklern auf der Grundlage der TypeScript-Typinferenz gute TypeScript-Unterstützung und Code-Tipps.

  • So verwenden Sie

  • Was die Installation von Pinia im Projekt betrifft, sollte jeder wissen, dass Sie es direkt über das Paketverwaltungstool installieren können.

1. Pinia-Instanz registrieren

Am Beispiel des Vue 3-Projekts müssen Sie es nur in der Eintragsdatei main.ts

eingeben, um die Registrierung von Pinia abzuschließen.
import { createApp } from 'vue'
import { createPinia } from 'pinia'

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

Da createApp natürlich Kettenaufrufe unterstützt, kann es auch direkt als

geschrieben werden Die Instanz wird in die App eingefügt und ein

app.config.globalProperties.$pinia

wird ebenfalls so konfiguriert, dass er auf die Instanz verweist.

2. Zustandsspeicher definieren

Beim Registrieren eines Pinia-Zustandsmoduls können Sie eine Zustandsmodulfunktion über die Methode

defineStore
erstellen (der Grund, warum es sich um eine Funktion handelt, liegt darin, dass sie in aufgerufen werden muss Form einer Funktion später) Holen Sie sich den Status darin). Die TypeScript-Definition der

deineStore-Funktion lautet wie folgt:

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 模块中调用该方法,保证此时能正确执行

最后

总的来说,Pinia 作为 Vue 官方推荐的状态库,配合 Vue 3 的组合式 API,可以更好的实现项目中各种数据状态的管理,而不是像以前使用 Vuex 一样通过 modules 的形式注册各种状态。Pinia 对于抽离逻辑进行复用(hooks),简化使用方式来说,比之前的 Vuex 好了很多倍;加上良好的类型支持与代码提示,让我们在开发过程中可以省去很多前置工作,也是对我们的开发效率的一种提升吧。

当然,、Vue DevTools 在更新之后,也实现了对 Pinia 的支持。

【相关视频教程推荐:vuejs入门教程web前端入门

Das obige ist der detaillierte Inhalt vonAusführliche Erklärung zur Verwendung der Vue3-Staatsverwaltungsbibliothek Pinia. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen