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中定义的属性)这种方式引用时才具备响应式。看下面这个例子:

<template>
  <div>
   <h1>count:{{appStore.count}}</h1>
    <h1>number:{{appStore.number}}</h1>
    <button @click="addCount">添加count</button>
    <button @click="addNumber">添加number</button>
  </div>
</template>

<script setup>
import useAppStore from "@/store/app.js"
import { ref } from 'vue'
import {storeToRefs} from "pinia"

const appStore=useAppStore()

const addCount=()=>{
  appStore.add(100)
}

</script>
<style  scoped>

</style>

在页面中我们通过访问appStore的数据此时才具备响应式。也就是此时我们点击添加count按钮,

appStore.count会做出正确的响应式更改。如果我们改成下面这样,那么count将一直是初始值

<template>
  <div>
   <h1>count:{{count}}</h1>
    <h1>number:{{number}}</h1>
    <button @click="addCount">添加count</button>
    <button @click="addNumber">添加number</button>
  </div>
</template>

<script setup>
import useAppStore from "@/store/app.js"

import {storeToRefs} from "pinia"

const appStore=useAppStore()

let count =appStore.count  //注意这里
let number=appStore.number  //注意这里

//let {count ,number}=appStore
 

const addCount=()=>{
  appStore.add(100)
}

</script>
<style  scoped>

</style

解构赋值和单独申明count和number去接收都将失去响应式

那如何实现数据的响应式呢?答案就是storeToRefs

storeToRefs大法,回归响应式

为了解决页面中解构赋值带来的响应式丢失问题。pinia提供了storeToRefs,这明显看齐了comopistionApi。和ref异曲同工

<template>
  <div>
   <h1>count:{{count}}</h1>
    <h1>number:{{number}}</h1>
    <button @click="addCount">添加count</button>
    <button @click="addNumber">添加number</button>
  </div>
</template>

<script setup>
import useAppStore from "@/store/app.js"

import {storeToRefs} from "pinia"

const appStore=useAppStore()
let {count ,number}=storeToRefs(appStore)
const addCount=()=>{
  appStore.add(100)
}

</script>
<style  scoped>

</style>

一劳永逸的this

为了兼容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互访

在项目中我们经常会在多个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

消失的mutation

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的类型支持的友好。这个见仁见智。

Logo

前往低代码交流专区

更多推荐