pini作为vue生态圈新出来的状态管理工具,因为相较vuex具备更简洁的语法和更好的ts支持,成了vue官方默认的状态管理新方案
我们在根目录下新建sore文件夹,新建index.js用于创建一个store。和vuex的用法一样我们需要在main.js中作为插件去激活,至此,pinia开始至在全局生效
// store/index.js
import {createPinia} from "pinia"
const store =createPinia()
export default store
//main.js
import { createApp } from 'vue'
import store from "./store"
import App from './App.vue'
const app=createApp(App)
app.use(store).mount('#app')
和 vuex通过module和namespace进行命名空间的聚合思想不同,pinia采用扁平化思想。各个store相互独立。互不干扰.
如下:我们新建两个store,一个名曰app,一个名曰 user
//store/app.js
import {defineStore} from "pinia"
const useAppStore = defineStore("app",{
state:()=>{
return{
count:1,
number:1
}
},
getters:{
bdCount(){
return this.count*2
}
},
actions:{
add(num){
this.count=num
}
}
})
export default useSAppStore
------------------------------------------------------------------
//store/user.js
import {defineStore} from "pinia"
const useUserStore=defineStore("user",()=>{
state:()=>{
return{
usename:"sena",
}
},
actions:{
changeName(name){
this.usename=name
}
}
})
export default useUserStore
注意:定义store事,第一个参数很重要。她用于在pinia内部区分不同store;二:state定义数据和vuex有点不一样。state的值是一个函数,全局的数据将被在该函数值作为返回值被抛出
和vuex中state数据的全局响应式不同。pinia中state中的数据仅仅在useStore.attr(attr为state中定义的属性)这种方式引用时才具备响应式。看下面这个例子:
count:{{appStore.count}}
number:{{appStore.number}}
在页面中我们通过访问appStore的数据此时才具备响应式。也就是此时我们点击添加count按钮,
appStore.count会做出正确的响应式更改。如果我们改成下面这样,那么count将一直是初始值
count:{{count}}
number:{{number}}
解构赋值和单独申明count和number去接收都将失去响应式
那如何实现数据的响应式呢?答案就是storeToRefs
为了解决页面中解构赋值带来的响应式丢失问题。pinia提供了storeToRefs,这明显看齐了comopistionApi。和ref异曲同工
count:{{count}}
number:{{number}}
为了兼容optionsAPI和vue2,pinia中采用了this,pinia把state和getters和actions中的定义的数据直接铺平挂在了this上。这一招直接省去了我们要通过state.xx,getters.xxx去获取state和getters中的数据。拿来即用。真是快哉
import {defineStore} from "pinia"
const useStore = defineStore("app",{
state:()=>{
return{
count:1,
number:1
}
},
getters:{
dbNum(){
return this.count*2 //通过this.count直接获取state中的count
}
},
actions:{
add(num){
console.log("this.dbNum:",this.dbNum) //通过this.count直接获取state中的dbNum
this.count=num
}
}
})
export default useStore
在项目中我们经常会在多个store数据间相互访问和修改。没有了命名空间和modules,pinia又是如何解决的呢?答案是直接引入。和在页面中一样通过useStore,获取到实例以后访问。暴力简单
我们以user中访问app中的count为例;
// store/app.js
import {defineStore} from "pinia"
const useStore = defineStore("app",{
state:()=>{
return{
count:1,
number:1
}
},
getters:{
dbNum(){
return this.count*2
}
},
actions:{
add(num){
console.log("this.dbNum:",this)
this.count=num
}
}
})
export default useStore
-----------------------------------------------------------------
import {defineStore} from "pinia"
import useSApptore from "./app"
const useUserStore=defineStore("user",()=>{
state:()=>{
return{
username:"sean",
userCount:0
}
},
getters:{
fullname(){
return this.username+"tian"
}
},
actions:{
changeAppCount(){
let app=useSApptore() //通过执行useSApptore得到appstore的实例
this.userCount=app.count //直接把app.count的值赋值给userstore下的userCount
}
}
})
export default useUserStore
pinia中虽然大多数写法和vuex一脉相承。但是有一个最大的不同就在于pinia中废弃了mutation,不管是同步的执行还是异步函数的处理,统一放在了actions中
不知道有没有注意到:pinia中的this,在vue2中大行其道的this,在vue3中默默的被函数式写法锁取代。那pinia中是否又有更好的偏向函数式的写法呢?当然。
我们改造下我们的user这个store文件
import {defineStore} from "pinia"
import {ref} from "vue"
import useSApptore from "./app"
const useUserStore=defineStore("user",()=>{
let username=ref("sean")
let usernum=ref(100)
const changeName=(name)=>{ //类似actions中的的函数
username.value=name
}
const upName=()=>{ //类似actions中的的函数
const appStore =useSApptore()
let anum=appStore.number
appStore.number=9999
}
const changeUserNum=()=>{ //类似actions中的的函数
usernum.value++
console.log(usernum.value)
}
const dbNum=()=>{ //类似我们gettters中的dbNum
return usernum.value*2
}
return {
username,
changeName,
upName,
changeUserNum,
dbNum
}
})
export default useUserStore
我们直接在ponia中摒弃了state.getters.actions。通过vue的ref做响应式处理、最后把这些函数和ref值都return 出去。这和vue组件中通过setup-()==>{return { xxx }}很像、对。就是这样。然后我们一样在页面中接收。同样能实现响应式。
这不过这样的方式,没有了state.getters.actions的定义,维护时,多少有一些费劲。但是函数式写法带来的好处则是ts的类型支持的友好。这个见仁见智。