Pinia入门:Vue.js状态管理者的初级指南

280 阅读6分钟

什么是Pinia

    Pinia是一个为Vue.js设计的状态管理库,它的设计目标是为了提供一种更简洁、更直观的方式来处理跨组件状态共享的问题。Pinia可以被视为Vue的Vuex库的一种替代方案,尤其是在Vue 3的背景下,它利用了Vue 3中引入的Composition API以及TypeScript的支持。

安装Pinia

    安装Pinia这很简单,在我们Vscode的Vue项目中打开终端输入

yarn add pinia 
# 或者使用 
npm npm install pinia

等待安装完成就好了

使用Pinia基础用法

    在使用Pinia之前,我们来探讨一个问题。在vue的组件通讯中存在父子组件通讯,子父组件通讯,那么如果我们想要兄弟组件通讯呢,又该如何实现。理论上来说我们可以由子组件1通过defineEmits声明一个事件,再由父组件通过订阅该事件获取到值,再通过v-bind绑定数据传给子组件2实现兄弟组件通讯,但是这样是否会显得工作量会大那么一丢丢呢。诶,所以我们就可以使用Pinin来完成,下面我将为大家介绍Pinia中的三个核心概念

Store

    Store是一个保存状态和业务逻辑的实体,它不会和组件树进行绑定,可以把它看成一个全局的实体,每一个组件都可以读取和写入它     我们在src文件夹下创建一个index.js文件,用于创建一个Pinia实例对象

import {createPinia} from 'pinia';

//创建一个仓库
const store = createPinia();

export default store;

这样我们创建好了一个Pinia实例对象,然后在我们全局文件main.js中引入并使用即可

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

createApp(App).use(store).mount('#app')

而定义一个Store也是挺简单的,在Pinia官方API文档中是这样写的

image.png

State

    State可以被理解为一个数据源的存在,它通常用来存放一些数据

image.png

Getter

    Getter可以被理解为Store中的一个计算属性,它专用于计算值

image.png

Action

    Action可以被理解为Store中的Method,里面可以下函数,值得注意的是 Getter中的函数天生带有一个形参state,代表仓库的数据源.

image.png

简单的综合运用

    现在就让我们简单的使用他们吧。首先我们先创建一个App.vue 文件,我们在src文件夹下的components文件夹下分别创建User.vueUpdate-user.vue文件。 我们再把User.vueUpdate-user.vue文件作为App.vue文件的子组件使用

//App.vue
<template>
        <div>
            <User/>
            <Updateuser />
        </div>
</template>

<script setup>
import User from './components/User.vue'
import Updateuser from './components/Update-user.vue'
</script>

<style lang="css" scoped>

</style>

现在我们分工一下User.vue中我们用于显示数据,Update-user.vue我们用于实现操作。最后在src文件下的store文件夹中创建user.js文件用于数据处理。 第一步我们首先要在user.js中定义一个Store,并给它设置一个唯一的Id

import {defineStore} from 'pinia';//defineStore 是store的一部分

export const useUserStore = defineStore({
    id:'user'
   })

然后我们把State,Getter,Action写好,在这里我给数据源State先写好一个userInfo对象

import {defineStore} from 'pinia';//defineStore 是store的一部分

export const useUserStore = defineStore({
    id:'user',
    state:()=>{ //整个仓库的数据源
        return {
            userInfo:{
                name:'老六',
                age:18,
                sex:'gril'
            }
        }
    },
    actions:{ //专门用来修改state中的数据
        
    },
    getters:{ //仓库中的计算属性
       
    }
})

然后我们需要在User.vue中引入useUserStore,通过调用useUserStore()得到useUserStore仓库,也就是

image.png

State中返回了一个对象userInfo所以我们可以直接获取到返回对象的值。因为我们的页面会进行数据修改,所以这里为大家介绍两种把数据变成响应式数据的方法,第一种是vue中自带的计算属computed,第二种是pinia中的storeToRefs

<template>
    <ul>
        <li>姓名:{{userStore.userInfo.name}}</li>
        <li>年龄:{{age}}</li>
        <li>十年之后:{{userStore.afterAge}}</li>
        <li>性别:{{userInfo.sex}}</li>
    </ul>
</template>

<script setup>
import {useUserStore} from '@/store/user'
import {computed} from 'vue'
import {storeToRefs} from 'pinia'

const userStore = useUserStore()//得到useUserStore仓库
const age = computed(()=>userStore.userInfo.age)
// 把仓库中的值包裹起来,变成响应式  其自带返回一个对象,需要结构
const {userInfo} = storeToRefs(userStore)

</script>

<style lang="css" scoped>

</style>

接下来让我们在Update-user中完成三个操作

<template>
    <button @click="changeName">修改仓库中的用户的姓名</button>
    <button @click="changeSex">修改仓库中的用户的性别</button>
    <button @click="changeAge">修改仓库中的用户的年龄</button>
</template>

修改姓名,修改年龄,更改性别。三个操作,所以我们定义三个函数ChangeName(),changeSex(),ChangeAge() 我们修改数据,是不是修改useuserStore中的数据,所以我们要调用useuserStore中自己的函数来实现数据修改。

<script setup>
import {useUserStore} from "@/store/user"
const userStore = useUserStore()
const changeName = () =>{
    // userStore.userInfo.name = '老王'
    userStore.changeUserName('老王');
}
const changeSex = () =>{
    // userStore.userInfo.sex = 'gril'
    userStore.changeUserSex('boy');
}
const changeAge = ()=>{
    userStore.changeUserAge(1)
}
</script>

我们分别调用useuserStore中自己的三个函数changeUserName,changeUserSex,changeUserAge,现在我们回到user.js中实现这三个函数

actions:{ //专门用来修改state中的数据
        changeUserName(name){
            this.userInfo.name = name
        },
        changeUserSex (sex){
            this.userInfo.sex = sex
        },
        changeUserAge(n){
            this.userInfo.age += n
        }
    }

this指代的是state.我们注意到在User.vue中还有一个是计算十年之后的年龄,这里我们就可以使用Getter计算属性了

getters:{ //仓库中的计算属性
        // getters中的函数天生带有一个形参state,代表仓库的数据源
        // getters中的函数名称就是这个函数返回出来的属性 不需要我们调用 我们直接userStore.afterAge就可以了
        afterAge(state){
            return state.userInfo.age+10
        }
    },

这样我们就基本实现了功能,但是依旧存在一个问题。当我们页面刷新之后,数据就会清零,需要重新执行。 所以我们给Store添加一个持久化数据的功能,用的是persist,这段内容我们先安装依赖

npm i pinia-plugin-persist

然后我们再把它引入index.js中,并使用

//index.js
import {createPinia} from 'pinia';
import piniaPluginPersist from 'pinia-plugin-persist'

//创建一个仓库
const store = createPinia();
store.use(piniaPluginPersist);

export default store;

然后在我们的user.js中实现

persist:{ //开启数据持久化
        enabled:true,
        strategies:[
            {
                paths:['userInfo'],
                // 持久化存储的位置
                storage:localStorage
            }
        ]
    }

paths是需要存入我们需要保存的数据,而storage是我们可以选择数据保存方式,在浏览器中我们有localStorage,Cookie,Session,IndexedDB等多种数据存储方式,这里我们选择localStorage的存储方式。 这样我们就实现了数据存储

image.png

D2FA23DBBB129A6C9D0D7F000AA7E777.gif

回到我们开始提到的兄弟组件如何实现兄弟组件之间通讯呢,这里我们的Update-user.vueUser.vue是兄弟组件,我们点击Update-user.vue中的按钮,就会修改User.vue展示的数据,这就完成兄弟组件通讯。

文章若有不足,恳请各位指出,感谢大家阅读!!

image.png