本文最后更新于: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
的全部内容
1 2 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的使用。该文件的内容基本固定,如下:
1 2 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定义的状态数据了,代码如下:
1 2 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中含有的参数:
1 2 3 4 5 6 7
| state: () => { return { info: 'I am Info', count: 1, count1: 1, } },
|
第一种方式和函数操作类似,直接在函数逻辑中操作即可。下面的操作就是在一个函数中对store中的数据进行操作:
1 2 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
方式更新。
1 2 3 4 5 6 7 8
| methods: { add1() { this.store.$patch({ count: this.store.count + 1, count1: this.store.count1 + 2, }) } }
|
第三种方式也是使用$patch
,上面的操作是传入一个对象,第三种方式是传入一个函数。传入函数的方式适合复杂逻辑的修改。
1 2 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()
方法(方法名任意),用来改变数据状态,代码如下:
1 2 3 4 5 6
| actions: { changeState(){ this.count++ this.info = 'I am really Info' } }
|
之后在相关组件的method中进行调用:
1 2 3 4 5
| methods: { add3(){ this.store.changeState(); } }
|
6.Pinia中getters的使用
Pinia中的getters和Vue中的计算属性类似,就是在获取State的值的时候做一些额外的处理。类似下面的代码逻辑。我们首先在getters
中定义下面的修改方法,就是在info后面直接加上haha:
1 2 3 4 5
| getters: { hahaInfo(state){ return state.info + "haha" } }
|
定义之后,可以直接像使用普通属性一样使用,使用插值表达式{{state.hahInfo}}
就可以直接显示在页面上。
getters是具有缓存特性的。我们可以在其中的方法里面增加一个console.log
进行输出,多次调用这个值,只会输出一次。
在上面的使用中我们是传入了一个state,当然也可以使用this。如果使用的是TypeScript,不传state,它无法自动推导出返回类型,这里标明返回类型即可。
1 2 3 4 5
| getters: { hahaInfo(): String { return this.info + "haha" } }
|
7.分文件的状态管理
在上面的例子中,我们都是使用store目录下的index.ts
进行说明的。而实际上我们也可以在store目录下创建更多的ts文件,来分文件进行全局状态管理。这样更有效果。例如我们可以创建store/counter.ts
,其中的内容定义与使用大体相同,只是在引用的时候需要如下使用。而只写这个@/store
目录的话,则是去访问index.ts
。
1 2 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 } })
|
下面是使用方式:
1 2 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)