Vue3状态管理库Pinia如何使用


这篇文章主要介绍“Vue3状态管理库Pinia如何使用”,在日常操作中,相信很多人在Vue3状态管理库Pinia如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue3状态管理库Pinia如何使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!Pinia 与 Vuex 一样,是作为 Vue 的“状态存储库”,用来实现 跨页面/组件 形式的数据状态共享。在平时的开发过程中,Vue 组件之间可以通过 PropsEvents 实现组件之间的消息传递,对于跨层级的组件也可以通过 EventBus 来实现通信。但是在大型项目中,通常需要在浏览器 保存多种数据和状态,而使用 Props/Events 或者 EventBus 是很难维护和扩展的。所以才有了 Vuex 和 Pinia。作为 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 在项目中的安装,大家应该都知道,直接通过包管理工具安装即可。以 Vue 3 项目为例,只需要在入口文件 main.ts 中引入即可完成 Pinia 的注册。

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

constapp=createApp(App)
constpinia=createPinia()
app.use(pinia)

当然,因为支持 createApp 支持 链式调用,所以也可以直接写成 createApp(App).use(createPinia()).mount('#app').此时 createPinia() 创建的是一个根实例,在 app.use 的时候会在 app 中注入该实例,并且配置一个 app.config.globalProperties.$pinia 也指向该实例。在注册一个 Pinia 状态模块的时候,可以通过 defineStore 方法创建一个 状态模块函数(之所以是函数,是因为后面调用的时候需要通过函数的形式获取到里面的状态)。deineStore 函数的 TypeScript 定义如下:

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

typeId=IDextendsstring
typestoreSetup=()=>SS
typeoptions=Omit,"id">|DefineStoreOptions|DefineSetupStoreOptions,_ExtractGettersFromSetupStore,_ExtractActionsFromSetupStore>

可以看到该函数最多接收 3个参数,但是我们最常用的一般都是第一种或者第二种方式。这里以 第一种方式 例,创建一个状态模块函数:

//该部分节选字我的开源项目vite-vue-bpmn-process
import{defineStore}from'pinia'
import{defaultSettings}from'@/config'
import{EditorSettings}from'types/editor/settings'

conststate={
editorSettings:defaultSettings
}

exportdefaultdefineStore('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 配置项包含三个部分:state:状态的初始值,推荐使用的是一个 箭头函数,方便进行类型推断getters:状态的获取,是一个对象格式;推荐配置为每个 getters 的对象属性为 箭头函数,方便进行类型推断;在使用时等同于获取该函数处理后的 state 状态结果;并且与 Vue 的计算属性一样,该方法也是惰性的,具有缓存效果actions:类似 Vue 中的 methods 配置项,支持异步操作,主要作用是 处理业务逻辑并更新状态数据;另外,此时的 actions 是一个 函数集合对象,与 getters 不同的是 不建议使用箭头函数并且函数内部的 this 就指向当前 store 的 state。注意: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'
importeditorStorefrom'@/store/editor'

exportdefaultdefineComponent({
setup(props){
consteditor=editorStore()

//直接获取state状态
const{editorSettings}=storeToRefs(editor)

//使用computed
consteditorSettings=computed(()=>editor.editorSettings)

//getters
constprefix=editor.getProcessEngine

//更新方式1:调用actions
editorStore.updateConfiguration({})

//更新方式2:直接改变state的值
editorStore.editorSettings={}

//更新方式3:调用$patch
editorStore.$patch((state)=>{
state.editorSettings={}
})

return{
editorStore
}
}
})

这里对以上几种处理方式进行说明:获取值:可以通过 解构 获取 state 定义的数据,但是 解构会失去响应式,所以需要用 storeToRefs 重新对其进行响应式处理通过 computed 计算属性,好处是 可以对 state 中的状态数据进行组合通过定义的 getters 方法来获取值,这种方式获取的结果本身就是 响应式的,可以直接使用更新值:首先是可以 直接改变 state 的状态值,缺点是多次使用容易有重复代码,且不好维护;也会影响代码的可读性通过定义的 actions 更新,也算是推荐方法之一;在后续迭代和扩展中,只需要维护好 store 中的代码即可$patch: 这个方式 可以接收一个对象或者函数,但是 推荐使用箭头函数(函数参数为状态数据 state);因为如果是对象,则需要根据新数据和当前状态 重建整个 state,增加了很多的性能损耗;而使用箭头函数,其实就与 actions 中的方式类似,可以 按代码逻辑修改指定的状态数据而在传统的 optionsAPI 模式的组件中(也没有配置 setup),Pinia 也提供了与 Vuex 一致的 API:mapState,mapGetters,mapActions,另外还增加了 mapStores 用来访问所有已注册的 store 数据,新增了 mapWritableState 用来 定义可更新状态;也因为 pinia 没有 mutations,所以也取消了 mapMutations 的支持。mapGetters 也只是为了方便迁移 Vu免费云主机域名ex 的组件代码,后面依然建议 使用 mapState 替换 mapGetters

{{settings}}{{processEngine}}mapStores 用来访问 所有已注册 store 状态。假设我们除了上文定义的 editor,还定义了一个 id 为 modeler 的 store,则可以这么使用:其中引用的所有 store,都可以通过 id + ‘Store’ 的形式在 Vue 实例中访问到。因为 Pinia 本身是支持各个 store 模块互相引用的,所以在定义的时候可以直接引用其他 store 的数据进行操作。例如我们这里根据 editor store 创建一个 modeler store

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

exportdefaultdefineStore('editor',{
state:()=>({
element:null,
modeler:null
}),
actions:{
updateElement(element){
consteditorStore=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'
constrouter=createRouter({
//...
})

//❌根据导入的顺序,这将失败
conststore=useStore()

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

router.beforeEach((to)=>{
//✅这将起作用,因为路由器在之后开始导航
//路由已安装,pinia也将安装
conststore=useStore()

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

直接在js模块的执行中 直接调用是可能会报错的,因为此时可能在 import router 的时候 还没有调用 createApp 和 createPinia 创建对应的应用实例和 pinia 根实例,所以无法使用。而在路由导航的拦截器中使用时,因为 路由拦截触发时,应用和 pinia 根实例肯定已经全部实例化完毕,才可以正常使用。所以 如果是在外部的 hooks 函数或者 utils 工具函数等纯函数模块中使用 store 数据时,最好是定义一个函数方法导出,在组件或者 store 模块中调用该方法,保证此时能正确执行到此,关于“Vue3状态管理库Pinia如何使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注百云主机网站,小编会继续努力为大家带来更多实用的文章!

相关推荐: 如何用C语言栈和队列实现回文检测功能

这篇文章主要介绍了如何用C语言栈和队列实现回文检测功能的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何用C语言栈和队列实现回文检测功能文章都会有所收获,下免费云主机域名面我们一起来看看吧。具体代码如下:运行结果:关于“如何用C语…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 02/16 16:06
下一篇 02/16 16:06

相关推荐