想学 pinia ?一文就够了
有时候不得不承认,官方的总结有时就是最精简的:
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。
虽然作为Vuex的升级版,但为了尊重原作者,所以取名pinia,而没有取名Vuex,所以大家可以直接将pinia比作为Vue3的Vuex,同时,pinia提供了一种更简洁、更直观的方式来处理应用程序的状态,更为重要的是,pinia的学习成本更低,低到一篇文章就能涵盖pinia的全部。
Pinia的安装与配置:
首先自然是安装pinia,在基于Vue3的项目环境中,提供了npm
与yarn
两种安装方式:
npm install pinia
yarn add pinia
随后,通常就是在src
目录下新建一个专属的store
文件夹,在其中的js
文件中创建并抛出这个仓库。
import { createPinia } from 'pinia' // 引入pinia模块
const store = createPinia() // 创建一个仓库
export default store // 抛出这个仓库
既然把这个仓库抛出了,那么现在便是让它能在全局起作用,于是在Vue的主要应用文件中(通常为main.js),引入使用pinia
。
import { createApp } from 'vue'
import App from './App3.vue'
import store from './store' //引入这个仓库
createApp(App).use(store).mount('#app') // 再use一下
这样一来pinia
仓库就能全局生效了!
Pinia的主要功能:
在官方文档中,Pinia提供了四种功能,分别是:
- Store:在Pinia中,每个状态管理模块都被称为一个Store。开发者需要创建一个Store实例来定义和管理状态。
- State:在Store中定义状态。可以使用defineState函数来定义一个状态,并通过state属性来访问它。
- Getters:类似于Vuex中的getters,用于从State中派生出一些状态。可以使用
defineGetters
函数来定义getters。 - Actions:在Pinia中,Actions用于处理异步操作或执行一些副作用。可以使用
defineActions
函数来定义Actions。
那么接下来我会通过一个具体的实例来表现出这四个功能,如下图:
分别是充当仓库的Store功能。存储子组件User.vue
中数据的State功能。另一个子组件Update-user.vue
中,点击按钮后数据会实现更新,也就是修改State中数据的Actions功能。与无论点击多少次” 经过一年后按钮 ”,页面都会实现同步更新的Getters功能。
State:
简单来说,State的作用就是作为仓库的数据源。
就比如说,我想在仓库的数据源里面放上一个对象来进行使用,那我们只需在先前创建的store
文件夹中再创建一个js
文件,这里我给它起名为user
,然后再其中这样添加对象。
(第一行引入的defineStore
代表defineStore
是store
的一部分。)
import { defineStore } from 'pinia' // defineStore 是 store 的一部分
export const useUserStore = defineStore({
id: 'user',
state: () => ({ // 仓库数据源
userInfo: {
name: '小明',
age: 18,
sex:'boy'
}
})
})
那么现在,我们想使用仓库中的数据就成为了一件非常容易的事。
正如上图,这里有一个父组件App.vue
,两个子组件User.vue
、Update-user.vue
。
父组件不做任何动作,只包含对两个子组件的引用:
<template>
<User/>
<Updateuser/>
</template>
<script setup>
import User from './components/User.vue'
import Updateuser from './components/Update-user.vue'
</script>
<style lang="css" scoped>
</style>
子组件User.vue:
可以看到在这个子组件中,我们通过import { useUserStore } from '@/store/user'
引用仓库,从而获得了仓库中小明姓名、年龄、性别的数据。
由于接下来的Update-user.vue
组件中会添加几个按钮对这些数据进行修改,那么我们就要把这些数据设置成响应式。
正常情况下,store
自带响应性,但如果我们不想每次都写userStore.userInfo.name
这么长一大串,就可以尝试将这些值取出来赋给其他变量:
这里有两种方法,第一种是引入computed
模块,如第14行年龄的修改。另一种是引入storeToRefs
模块,这是一种属于Pinia
仓库的模块,将整个userInfo
变成响应式。
于是接下来,就轮到我们的Actions登场了
<template>
<ul>
<li>姓名:{{ userStore.userInfo.name }}</li>
<li>年龄:{{ age }}</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()
const age = computed(() => userStore.userInfo.age) // 1. 计算属性使响应式能生效
const { userInfo } = storeToRefs(userStore) // 2. 专门包裹仓库中函数用来返回对象
</script>
<style lang="scss" scoped>
</style>
Actions:
简单来说,Actions的作用就是专门用来修改State,如果你想要修改仓库中的响应式元素,只需要进行两步操作:
第一步:在user.js
也就是我们的仓库中添加actions
,专门设置函数用来修改state对象中的值。例如changeUserName
作用是修改姓名, changeUserSex
作用是修改性别。
import { defineStore } from 'pinia' // defineStore 是 store的一部分
export const useUserStore = defineStore({
id: 'user',
state: () => ({ // 仓库数据源
userInfo: {
name: '小明',
age: 18,
sex:'boy'
}
}),
actions: { // 专门用来修改state
changeUserName(name) {
this.userInfo.name = name
},
changeUserSex(sex){
this.userInfo.sex = sex
}
}
})
子组件Update-user.vue:
第二步,在控制按钮的组件Update-user.vue
中触发这两个函数,就如第10与14行的两个箭头函数。
<template>
<button @click="changeName">修改仓库中用户姓名</button>
<button @click="changeSex">修改仓库中用户性别</button>
</template>
<script setup>
import { useUserStore } from '@/store/user' // 引入Pinia仓库
const userStore = useUserStore() // 声明仓库
const changeName = () => { // 触发提供的函数
userStore.changeUserName('小红')
}
const changeSex = () => {
userStore.changeUserSex('gril')
}
</script>
<style lang="css" scoped>
</style>
这样一来,依赖于Actions,我们就成功完成了响应式修改仓库中数据的功能,也就是前两个按钮的功能!
Getters:
简单来说Getters就是仓库中的计算属性。
现在我们来实现第三个按钮功能,首先就是在User.vue
组件中第5行,添加 “ 十年之后年龄 ” 一栏:
<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()
const age = computed(() => userStore.userInfo.age)
const { userInfo } = storeToRefs(userStore)
</script>
<style lang="scss" scoped>
</style>
那么现在你一定能注意到这一栏其中的userStore.afterAge
,这正是我们将在getters中返回的值。
那么关于getters,具体的使用方法就是继续在user.js
中添加进getters,我们在其中打造了一个afterAge
函数来返回userStore.afterAge
,正如第25行。
import { defineStore } from 'pinia' // defineStore 是 store的一部分
export const useUserStore = defineStore({
id: 'user',
state: () => ({ // 仓库数据源
userInfo: {
name: '小明',
age: 18,
sex:'boy'
}
}),
actions: { // 专门用来修改state
changeUserName(name) {
this.userInfo.name = name
},
changeUserSex(sex){
this.userInfo.sex = sex
},
changeUserAge(age){ // 新添加的一年后年龄计算方法
this.userInfo.age += age
}
},
getters: { // 仓库中的计算属性,所依赖的值改变会重新执行
afterAge(state) {
return state.userInfo.age + 10
}
}
})
准备工作完毕,现在就该在页面上添加这个按钮,于是在组件Update-user.vue
添加上按钮与执行函数。
<button @click="changeAge">经过一年后</button>
const changeAge = () => {
userStore.changeUserAge(1)
}
有了这些之后,这个项目的功能便彻底完善,无论点击多少次“ 经过一年后 ”按钮,在页面上显示的值都是正确且实时更新的,这就是Getters的功劳!
补充:数据持久化
关于整个项目的功能实现确实已经结束,但人的贪心却是不得满足的,如果我们想要在原有的基础上实现网页刷新数据却不刷新,也就是说数据的持久化,那又该怎么办呢?
很简单,也就是堪堪三步,便能实现。
第一步:安装persist
插件。
npm i pinia-plugin-persist
第二步:在store
的js
文件中引入这个插件。
import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist' //引入插件
const store = createPinia()
store.use(piniaPluginPersist) // 使用插件
export default store
第三步:在我们前文user.js
的defineStore
库内继续添加上persist
功能。
persist: { // 持久化
enabled: true,
strategies: [ // 里面填想要持久化的数据
{
paths: ['userInfo'], // 指明持久化的数据
storage: localStorage // 指明存储
}
]
}
现在可以看到点击按钮后的数据都被存储到浏览器的存储空间中,无论多少次刷新都不会被重置!
最后:
至此,这样一个简简单单的项目,却解释清楚了Pinia功能的核心,读完这篇文章,相信每一个学习Pinia的人都能有所收获。
来源:juejin.cn/post/7407407711879807026