피니아란 무엇인가요? 사용하는 방법? 이 기사는 Vue의 차세대 상태 관리 라이브러리인 Pinia에 대해 알아보는 데 도움이 되기를 바랍니다.
2020년 9월 Vue 3 공식 버전이 출시된 후 Vuex도 2021년 2월 Vue 3에 적용된 4.0 버전을 출시했습니다. 그러나 2021년 8월 말에는 주로 Eduardo, Vue 핵심 팀의 구성원입니다. 새로운 Vue 상태 공유 라이브러리 출시 버전 2.0이었으며 같은 해 11월 Youda는 공식적으로 Pinia를 Vue의 공식 상태 라이브러리로 지정했습니다(현재 Vue 공식 웹사이트는 Vuex를 Pinia로 대체했습니다). ). (학습 영상 공유: vue 영상 튜토리얼)
Pinia는 Vuex와 마찬가지로 Vue의 "상태 저장소"로, 교차 페이지/구성 요소 형태의 데이터 상태를 구현하는 데 사용됩니다. 공유.
일반적인 개발 과정에서 Vue 구성 요소는 Props 및 Events를 통해 서로 통신할 수 있습니다. 크로스 레벨 구성 요소의 경우 EventBus를 통해서도 통신할 수 있습니다. 그러나 대규모 프로젝트에서는 일반적으로 여러 데이터와 상태를 브라우저에 저장해야 하며 Props/Events 또는 EventBus를 사용하는 것은 유지 관리 및 확장이 어렵습니다. 따라서 Vuex와 Pinia가 있습니다.
mutations. 대부분의 개발자의 눈에 돌연변이는 상태 데이터의 동기 수정만 지원하고 actions은 비동기를 지원하지만 상태를 수정하려면 여전히 내부적으로 돌연변이를 호출해야 하기 때문에 이는 의심할 여지 없이 매우 번거롭고 중복됩니다
유형 추론을 최대한 활용합니다
Vuex는 인스턴스/Vue에 상태 종속성을 주입해야 합니다. 프로토타입이지만 상태 모듈을 직접 도입하고 getter/actions 함수를 호출하여 상태 업데이트 획득을 완료합니다. TypeScript 및 유형 추론에 대한 우수한 지원으로 인해 개발자는 매우 뛰어난 코드 팁을 즐길 수 있습니다
상태 데이터 사전 등록, 기본적으로 코드 로직에 따라 자동으로 처리되며 사용 중에 언제든지 새 상태를 등록할 수 있습니다
Vuex 모듈 내장 세트 구조가 없으며 모든 상태가 평면적으로 관리됩니다 . pinia에 의해 등록된 상태는 vuex의 모듈과 유사하다는 것도 이해할 수 있습니다. 단, pinia는 모든 상태 모듈을 등록하기 위해 통일된 입구가 필요하지 않습니다
Vuex 전역 상태 공유 기능 실현을 전제로 Pinia는 상태 저장 구조를 개선하고 사용을 최적화하며 API 디자인 및 사양을 단순화하고 TypeScript 유형 추론을 기반으로 개발자에게 우수한 TypeScript 지원 및 코드 팁을 제공합니다.사용 방법
1. Pinia 인스턴스 등록
에 이를 도입하기만 하면 Pinia 등록이 완료됩니다. import { createApp } from 'vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
체인 콜createPinia()을 지원하기 때문에 .
로 직접 작성할 수도 있습니다. 이때createApp(App).use(createPinia()).mount('#app')
는 app.use가 실행될 때 루트 인스턴스를 생성합니다. 인스턴스가 앱에 삽입되고 app.config.globalProperties.$pinia도 인스턴스를 가리키도록 구성됩니다.
2. Define state Store메소드를 통해 상태 모듈 함수를 생성할 수 있습니다. (함수인 이유는 나중에 함수 형식) 내부에서 상태를 가져옵니다. 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 配置项包含三个部分:
注意:getters 的函数定义中 第一个参数就是当前 store 的状态数据 state,而 actions 中的函数参数为 实际调用时传递的参数,可以传递多个,内部通过 this 上下文 直接访问 state 并进行更新。
众所周知,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 方法来获取值,这种方式获取的结果本身就是 响应式的,可以直接使用
更新值:
而在传统的 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 实例中访问到。
因为 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 } } })
因为 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 的支持。
위 내용은 Vue3 상태 관리 라이브러리 Pinia 사용법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!