本文最后更新于:2023-03-30T21:26:46+08:00
                  
                  
                
              
            
            
              
                
                Pinia状态管理
1.Pinia的简介
Pinia是Vue生态中Vuex的代替者,是一个全新的Vue状态管理库。对比Vuex来说,Pinia有五大优势:
- 对Vue2、Vue3都支持
- 抛弃了Mutations操作,只有state、getters和actions,极大简化了状态管理库的使用,让代码编写更加容易直观
- 不需要嵌套模块,符合Vue3的Composition API
- 完整的TypeScript支持
- 代码更加简洁
2.Pinia的基本使用
首先需要安装pinia,只需要简单执行下面命令即可。
之后我们需要在main.ts中进行引入,并进行挂载,下面是main.ts的全部内容
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | import {createApp} from 'vue'import App from './App.vue'
 import {createPinia} from "pinia"
 
 import './assets/main.css'
 
 
 const pinia = createPinia()
 const app = createApp(App)
 
 
 app.use(pinia)
 app.mount('#app')
 
 | 
3.store状态管理库的创建
在/src目录下新建store文件夹,再创建一个index.ts文件,在这个文件中,主要完成状态容器的定义,修改容器中的state和仓库中action的使用。该文件的内容基本固定,如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | import {defineStore} from 'pinia'
 export const mainStore = defineStore('main', {
 state: () => {
 return {
 info: 'I am Info'
 }
 },
 getters: {},
 actions: {}
 })
 
 | 
- state:用来存储全局的状态,其中状态的创建与组件中的data类似,
- getters:在获取状态的时候进行某种处理
- actions:用来修改state全局状态数据
4.store数据的读取
定义了store状态之后,我们就可以在组件中读取对应的数据。先引入mainStore,然后在setup阶段通过mainStore得到store实例,之后就可以在组件里调用store里state定义的状态数据了,代码如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | <template><div>
 I am Test
 <h2>{{ store.info }}</h2>
 </div>
 </template>
 
 <script>
 import {mainStore} from "@/store"
 
 export default {
 name: "Test",
 setup() {
 const store = mainStore()
 
 return {
 // 您可以返回整个 store 实例以在模板中使用它
 store,
 }
 },
 
 }
 </script>
 
 | 
5.改变状态数据
在Pinia中修改状态数据有多种方式。后续的举例代码中,对state进行操作,所以这里先明确目前state中含有的参数:
| 12
 3
 4
 5
 6
 7
 
 | state: () => {return {
 info: 'I am Info',
 count: 1,
 count1: 1,
 }
 },
 
 | 
第一种方式和函数操作类似,直接在函数逻辑中操作即可。下面的操作就是在一个函数中对store中的数据进行操作:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import {mainStore} from "@/store";
 export default {
 name: "MyButton",
 setup() {
 const store = mainStore()
 
 return {
 store,
 }
 },
 methods:{
 add(){
 this.store.count++;
 }
 }
 }
 
 | 
第二种方式是使用Pinia中的$patch方式,同样是写在method中,但是调用$patch方式。Pinia
的官方网站,已经明确表示$patch的方式是经过优化的,会加快修改速度,对程序的性能有很大的好处。所以如果是多条数据同时更新状态数据,推荐使用$patch方式更新。
| 12
 3
 4
 5
 6
 7
 8
 
 | methods: {add1() {
 this.store.$patch({
 count: this.store.count + 1,
 count1: this.store.count1 + 2,
 })
 }
 }
 
 | 
第三种方式也是使用$patch,上面的操作是传入一个对象,第三种方式是传入一个函数。传入函数的方式适合复杂逻辑的修改。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | methods: {add2() {
 this.store.$patch((state) => {
 state.count++
 if (state.info === "I am Info") {
 state.info = "I am not Info"
 }
 })
 }
 }
 
 | 
第四种方式是在actions中写好修改逻辑,然后再调用actions。如果一个修改的过程非常复杂,可以先定义好actions中的函数,然后在组件里调用函数。如下过程所示。
首先在/src/store/index.ts中的actions编写一个changeState()方法(方法名任意),用来改变数据状态,代码如下:
| 12
 3
 4
 5
 6
 
 | actions: {changeState(){
 this.count++
 this.info = 'I am really Info'
 }
 }
 
 | 
之后在相关组件的method中进行调用:
| 12
 3
 4
 5
 
 | methods: {add3(){
 this.store.changeState();
 }
 }
 
 | 
6.Pinia中getters的使用
Pinia中的getters和Vue中的计算属性类似,就是在获取State的值的时候做一些额外的处理。类似下面的代码逻辑。我们首先在getters中定义下面的修改方法,就是在info后面直接加上haha:
| 12
 3
 4
 5
 
 | getters: {hahaInfo(state){
 return state.info + "haha"
 }
 }
 
 | 
定义之后,可以直接像使用普通属性一样使用,使用插值表达式{{state.hahInfo}}就可以直接显示在页面上。
getters是具有缓存特性的。我们可以在其中的方法里面增加一个console.log进行输出,多次调用这个值,只会输出一次。
在上面的使用中我们是传入了一个state,当然也可以使用this。如果使用的是TypeScript,不传state,它无法自动推导出返回类型,这里标明返回类型即可。
| 12
 3
 4
 5
 
 | getters: {hahaInfo(): String {
 return this.info + "haha"
 }
 }
 
 | 
7.分文件的状态管理
在上面的例子中,我们都是使用store目录下的index.ts进行说明的。而实际上我们也可以在store目录下创建更多的ts文件,来分文件进行全局状态管理。这样更有效果。例如我们可以创建store/counter.ts,其中的内容定义与使用大体相同,只是在引用的时候需要如下使用。而只写这个@/store目录的话,则是去访问index.ts。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | import { ref, computed } from 'vue'
 import { defineStore } from 'pinia'
 
 export const useCounterStore = defineStore('counter', () => {
 const count = ref(0)
 const doubleCount = computed(() => count.value * 2)
 function increment() {
 count.value++
 }
 
 return { count, doubleCount, increment }
 })
 
 | 
下面是使用方式:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | import { useCounterStore } from '@/stores/counter'
 
 export default {
 setup() {
 const counter = useCounterStore()
 
 counter.count++
 
 counter.$patch({ count: counter.count + 1 })
 
 counter.increment()
 
 return {
 counter
 }
 },
 }
 
 | 
参考文章
- 介绍 | Pinia
中文文档 (web3doc.top)
- 技术胖-Pinia入门视频教程
全新一代状态管理工具Pinia -Vue3全家桶系列 (jspang.com)