Pinia - 符合直觉的Vue.js状态管理库
集中式状态(数据)管理,把需要共享的数据交给pinia管理
准备一个效果

搭建 pinia 环境
第一步:npm install pinia
第二步:操作src/main.ts
1 | import { createApp } from 'vue' |
此时开发者工具中已经有了pinia
选项

存储+读取数据
Store
是一个保存:状态、业务逻辑 的实体,每个组件都可以读取、写入它。它有三个概念:
state
、getter
、action
,相当于组件中的:data
、computed
和methods
。具体编码:
src/store/count.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
// 推荐和定义hooks一样用use命名
export const useCountStore = defineStore('count',{
// 动作
actions:{},
// 状态
state(){
return {
sum:6
}
},
// 计算
getters:{}
})具体编码:
src/store/talk.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
export const useTalkStore = defineStore('talk',{
// 动作
actions:{},
// 状态
state(){
return {
talkList:[
{id:'yuysada01',content:'你今天有点怪,哪里怪?怪好看的!'},
{id:'yuysada02',content:'草莓、蓝莓、蔓越莓,你想我了没?'},
{id:'yuysada03',content:'心里给你留了一块地,我的死心塌地'}
]
}
},
// 计算
getters:{}
})组件中使用
state
中的数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<template>
<h2>当前求和为:{{ sumStore.sum }}</h2>
</template>
<script setup lang="ts" name="Count">
// 引入对应的useXxxxxStore
import {useSumStore} from '@/store/sum'
// 调用useXxxxxStore得到对应的store
const sumStore = useSumStore()
// 虽然sumStore里面的sum是个ObjectRefImpl对象,但是这里,不能.value,会报错
// 如let obj = reactive({a:1,b:1,c:ref(9)}),
// 这里的c就应该直接obj.c,而不能加.value,因为外面已经帮我们处理好了
console.log(sumStore.sum) // 直接拿
console.log(sumStore.$state.sum) // 也可以这样,但是没必要
</script>1
2
3
4
5
6
7
8
9
10
11
12
13
14<template>
<ul>
<li v-for="talk in talkStore.talkList" :key="talk.id">
{{ talk.content }}
</li>
</ul>
</template>
<script setup lang="ts" name="Count">
import axios from 'axios'
import {useTalkStore} from '@/store/talk'
const talkStore = useTalkStore()
</script>
修改数据(三种方式)
第一种修改方式,直接修改(vuex中不允许直接修改,要借助mutation)
1
countStore.sum = 666
第二种修改方式:批量修改
1
2
3
4countStore.$patch({
sum:999,
school:'atguigu'
})第三种修改方式:借助
action
修改(action
中可以编写一些业务逻辑)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import { defineStore } from 'pinia'
export const useCountStore = defineStore('count', {
/*************/
actions: {
//加
increment(value:number) {
if (this.sum < 10) {
//操作countStore中的sum
this.sum += value
}
},
//减
decrement(value:number){
if(this.sum > 1){
this.sum -= value
}
}
},
/*************/
})组件中调用
action
即可1
2
3
4
5// 使用countStore
const countStore = useCountStore()
// 调用对应action
countStore.incrementOdd(n.value)
storeToRefs
在组件中,我们每次使用store里的值,都需要在模版中如
{{countStore.sum}}
,每次使用都需要前面这一大长串。于是我们可以想到解构赋值:const { sum, school } = countStore
,但是这样数据就失去了响应式!
虽然可以借助toRefs:const { sum, school } = Refs(countStore)
但是我们打印一下这个Refs(countStore)
,可以发现它把整个store里面所有的属性(数据和方法)都打成了ref,虽然实现了,但是代价有点大
所以,我们可以使用 ——storeToRefs
借助
storeToRefs
将store
中的数据转为ref
对象,方便在模板中使用。注意:
pinia
提供的storeToRefs
只会将数据做转换,不会对方法进行ref包裹;而Vue
的toRefs
会转换store
中所有数据。所取属性的数据类型:
- 基本类型需要包裹,脚本文件中.value使用
- 对象类型可以直接解构出来(还是响应式的),也可以包裹(脚本文件中.value使用)
直接解构:const { talkList } = talkStore
,然后直接talkList使用
包裹解构:const { talkList } = storeToRefs(talkStore)
,在脚本文件中需要talkList.value
使用
和toRefs基本一致?
1 | <template> |
getters
概念:当
state
中的数据,需要经过处理后再使用时,可以使用getters
配置。追加
getters
配置。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27// 引入defineStore用于创建store
import {defineStore} from 'pinia'
// 定义并暴露一个store
export const useCountStore = defineStore('count',{
// 动作
actions:{
/************/
},
// 状态
state(){
return {
sum:1,
school:'atguigu'
}
},
// 计算
getters:{
// 如果不用this,这里就可以写成 箭头函数
bigSum:(state):number => state.sum *10,
upperSchool():string{
// this就是store
return this.school.toUpperCase()
},
printThis:()=>this, // 得到的是undefined
}
})组件中读取数据:
1
2const {increment,decrement} = countStore
let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)
$subscribe
通过 store 的 $subscribe()
方法侦听 state
及其变化
- mutate:本次修改的信息
- state:真正的数据
1 | // 组件中 |
1 | state(){ |
store组合式写法
就和setup语法糖很像
数据直接用ref、reactive去定义
直接写函数,就是actions函数
getters直接写computed
必须return出去
缺点:页面数据多的时候,一堆return
优点:不用写那么多层次和结构,清晰一点,易于维护
选项式优点:易于理解和迁移,与传统的Vuex风格相似
缺点:代码量增加,不够简洁,尤其是在大型项目中
1 | import {defineStore} from 'pinia' |