当前位置: 首页 > Web前端 > vue.js

上手 Vue 新的状态管理 Pinia,一篇文章就够了

时间:2023-03-31 21:54:32 vue.js

一篇文章足以入门Vue新的状态管理Pinia,并且已经收录在官方github中。有了Vuex,为什么还要再开发一个Pinia?先来一张图,看看当时对Vuex5的提案,下一代的Vuex5应该是这个样子。Pinia完全符合他当时Vuex5提案中提到的功能,所以说Pinia是Vuex5也不为过,因为它的作者是官方开发者,已经被官方接手了,但是目前Vuex和Pinia还是两个独立的仓库,以后可能会合并或者独立开发,但是官方一定要推荐Pinia,因为在Vue3中使用Vuex,在Vuex中需要使用Vuex4,只能作为过渡的选择,其中有很大的缺陷。因此,在CompositionAPI诞生后,设计了新的状态管理PiniaPinia和VuexVuex:State,Gettes,Mutations(同步),Actions(异步)4.xVuex4用于Vue3Vuex3用于Vue2Pinia目前最新版本是2.x,同时支持Vue2和Vue3目前来看,Pinia比Vuex好很多,解决了Vuex的很多问题,所以笔者也强烈推荐使用Pinia直接,特别是TypeScript项目Pinia核心特性Pinia没有MutationsActions支持同步和异步嵌套结构没有模块Pinia在设计上提供了一个扁平化的结构,这意味着每个store都是相互独立的,不属于任何人,即,它被扁平化,代码分割更好,没有命名空间。当然你也可以通过在一个模块中导入另一个模块来隐式嵌套存储,你甚至可以对存储有循环依赖更好的TypeScript支持不再需要创建自定义复杂包装器来支持TypeScript一切都是类型化的,API的设计也尽可能使用TS类型推断。无需注入、导入函数和调用它们。享受自动补全,让我们的开发更加方便。无需手动添加商店,其模块默认自动注册。除了初始安装和SSR配置之外,Vue2和Vue3都支持相同的API。它们支持VueDevTools来跟踪操作,并且可以在使用该模块的组件中观察到变化的时间线。模块本身支持时间。-旅行更容易调试。在Vue2中,Pinia会使用到Vuex的所有接口,所以不能混用。但是对Vue3的调试工具支持并不完善。比如没有穿越功能模块。热更新无需重新加载页面即可修改模块热更新时,将保持任何现有状态。支持插件扩展。支持Pinia功能。Pinia的服务器端渲染。以Vue3+TypeScript为例,安装npminstallpiniamain.ts。从'pinia'createApp(App)初始化配置导入{createPinia}。use(createPinia()).mount('#app')以在store目录下创建一个user.ts为例,我们先定义并导出一个名为user的模块import{defineStore}from'pinia'exportconstuserStore=defineStore('user',{state:()=>{return{count:1,arr:[]}},getters:{...},actions:{...}})defineStore首先有两个参数第一个参数是模块的名称,必须是唯一的。多个模块不能有相同的名称。Pinia会将所有模块挂载到根容器。第二个参数是一个对象,里面的options该项目与Vuex几乎相同。状态用于存储全局状态。它必须是箭头函数。为了避免服务端渲染时交叉请求造成的数据状态污染,只能是函数,为了更好的TS,必须使用箭头函数。类型推导getter用于封装计算属性,具有缓存的功能。Actions用于封装业务逻辑、修改状态和访问状态。比如我们要在页面中访问state中的属性count。因为defineStore会返回一个函数,我们必须先调用它。获取数据对象,然后就可以在模板中直接使用了'../store'constuser_store=userStore()//解构//const{count}=userStore()比如像注释那样解构使用是没有问题的,注意一下,所以你可以得到它数据没有响应。如果你想解构并保持响应,你需要使用一个方法storeToRefs()。示例如下store'const{count}=storeToRefs(userStore)原因是Pinia实际上使状态数据具有反应性。和Vue3的reactive一样,解构出来的是没有responsive的,所以需要做refresponsiveproxygetters,和Vuex的getters一样,也有缓存功能在页面中多次使用如下,第一次会调用getter,如果数据没有变化,后面会读取缓存注意两种方法的区别,在注释getters中写:{//方法一,接收一个可选参数statemyCount(state){console.log('Called')//在页面使用了三次,这里只会执行一次,然后缓存起来returnstate.count+1},//方法二,不传参,使用this//但必须指定函数返回值的类型,否则无法推导出类型myCount():number{returnthis.count+1}}update和update有四种方式状态中的数据和动作。我们先来看三个简单的更新,解释一下写在注释中scriptlang="ts"setup>import{userStore}from'../store'constuser_store=userStore()consthandleClick=()=>{//方法一user_store.count++//方法二,需要修改多个数据,建议使用$patch批量更新,通过输入一个对象user_store.$patch({count:user_store.count1++,//arr:user_store.arr.push(1)//Errorarr:[...user_store.arr,1]//是的,但是你必须解构整个数组,所以这是不必要的})//使用$patch以获得更好的性能,因为多次数据更新只会更新视图一次//方法三,或者$patch,传入函数,第一个参数是stateuser_store.$patch(state=>{state.count++state.arr.push(1)})}第四种方法,当逻辑或者请求比较多的时候,我们可以封装在示例中store/user.ts中的action中传递参数,或者直接通过this.xx来获取数据state中需要注意的是action不能用箭头函数定义,否则外部的this会绑定actions:{changeState(num:number){//不能使用箭头函数this.count+=num}}调用consthandleClick=()=>{user_store.changeState(1)}支持VueDevtools打开开发者工具的VueDevtools会发现Pinia,可以手动修改data用于调试,模拟调用接口非常方便示例:先定义示例接口api/user.ts//接口数据类型exportinterfaceuserListType{id:numbername:stringage:number}//模拟数据请求接口返回constuserList=[{id:1,name:'张三',age:18},{id:2,name:'李四',age:19},]//封装了一个定时器模拟异步效果asyncfunctionwait(delay:number){returnnewPromise((resolve)=>setTimeout(resolve,delay))}//interfaceexportconstgetUserList=async()=>{awaitwait(100)//延迟100毫秒返回returnuserList}然后将调用接口封装在store/user.ts中的actions中import{defineStore}from'pinia'import{getUserList,userListType}from'../api/user'exportconstuserStore=defineStore('user',{state:()=>{return{//用户列表list:[]asuserListType//类型转换touserListType}},actions:{asyncloadUserList(){constlist=awaitgetUserList()this.list=list}}})调用页面上的动作发起请求跨模块修改数据在一个模块的动作中,需要修改另一个模块的状态数据例子:比如修改用户模块中的某个用户的名字聊天模块//chat.tsim端口{defineStore}来自'pinia'import{userStore}from'./user'exportconstchatStore=defineStore('chat',{actions:{someMethod(userItem){userItem.name='newname'constuser_store=userStore()user_store.updateUserName(userItem)}}})user模块//user.tsimport{defineStore}from'pinia'exportconstuserStore=defineStore('user',{state:()=>{return{list:[]}},actions:{updateUserName(userItem){constuser=this.list.find(item=>item.id===userItem.id)if(user){user.name=userItem.name}}}})结论如果本文对您有帮助如果对你有一点帮助,点个赞支持一下。你们的每一个【点赞】,都是我创作最大的动力。感谢大家的支持^_^扫描二维码关注公众号,可以加我为好友,我拉你进前端交流群,一起交流,共同进步