Pinia
鹿酒 2022/2/13 PiniaVueJavaScript
Pinia是Vue的状态管理库,类似Vuex,Vue2/3 都支持。
文章中代码按照vue3写法实现,默认<script lang="ts" setup><script>。
Pinia的使用更符合直觉,且支持多个状态库,相比Vuex更简单明了
# 特点
- 非常精简
- 支持ts,不用做其他操作
- 模块化设计,
- 没有 mutations,自动记录state变化
- 可以扩展插件
# 核心概念与使用
# 引用
import { createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)
1
2
3
2
3
# Store
保存数据和方法的【仓库】
# 初始化仓库
直接解构会使数据失去响应性!
src/store/index
import {defineStore} from 'pinia'
export const mainStore = defineStore('main', {
state: ()=>{
return {
number: 0,
}
},
getters: {},
actions: {},
})
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 从仓库里取值
xx/xx.vue
<template>
<div>{{store.number}}</div>
</template>
<script>
import {mainStore} from '../store/index'
import {storeToRefs} from 'pinia'
const store = mainStore()
// 解构赋值
const { number } = store // Wrong: 直接使用 只会取到第一次赋的值
const { number } = storeToRefs(store) // Right:正确的解构赋值
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# 修改仓库中的值
store的值可以直接修改,也可以用store.$patch来批量赋值
import {mainStore} from '../store/index'
import {storeToRefs} from 'pinia'
const store = mainStore()
// store直接赋值
store.number = 10
// store.$patch批量赋值 优点 批量操作性能比直接赋值强
store.$patch({
num: 11,
phone: 13211112222
})
// 处理复杂业务逻辑 也可以传递方法直接修改
store.$patch((state)=>{
state.num = 12;
})
// action调用方法
// 下面有代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 监听数据
监听store数据的变更
mutations: 事件
state: store对象
// xx/xx.vue
store.$subscribe((mutations, state)=>{
console.log(mutations, state, state.count);
})
1
2
3
4
2
3
4
# 监听action
监听action的调用情况
name: 调用的action的方法
store: store对象
args: 调用次数
after: action调用完成后回调
onError: 抛出异常
// xx/xx.vue
store.$onAction(({name, store, args, after, onError})=>{
console.log(name, store, args, after, onError, 'action');
})
1
2
3
4
2
3
4
# Getter
# 读取数据的方法
使用getter中定义的方法读取数据 在数据源未改变时 有缓存机制 不会重复调用,性能由于普通函数计算
// src/store/index
import {defineStore} from 'pinia'
export const mainStore = defineStore('main', {
state: ()=>{
return {
phone: 18612348899,
}
},
getters: {
phoneFormat():String{
return this.phone.toString().replace(/^(\d{3})(\d{4})(\d{4})/, '$1-$2-$3')
}
},
})
// xx/xx.vue
import {mainStore} from '../store/index'
import {storeToRefs} from 'pinia'
const store = mainStore()
const {phoneFormat} = storeToRefs(store)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# action
操作数据的方法
src/store/index
import {defineStore} from 'pinia'
export const mainStore = defineStore('main', {
state: ()=>{
return {
count: 0,
}
},
actions: {
changeCount(num: number){
this.count+=num
}
},
})
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
xx/xx.vue
<template>
<div>
{{store.count}}
<button @click="handleClick">handleClick</button>
</div>
</template>
<script setup lang="ts">
import {mainStore} from '../store/index'
import {storeToRefs} from 'pinia'
const store = mainStore()
// action调用方法 适合有公共数据处理的情况
const handleClick = function(){
store.changeCount(1)
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Store的相互调用
// store/goods
import {defineStore} from 'pinia'
export const goodsStore = defineStore('goods', {
state: ()=>{
return {
id: '123123',
name: '商品名称',
qty: 0,
}
},
})
// store/index
import {defineStore} from 'pinia'
import {goodsStore} from './goods' // 另一个仓库
export const mainStore = defineStore('main', {
actions: {
getGoods(){
const goods = goodsStore()
return `商品ID:${goods.id};商品名称:${goods.name};加购数量:${goods.qty}。`
}
},
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 总结
Pinia比Vuex简单很多,而且支持扩展。
Pinia更符合直觉用着更顺手。
TestCode Link (opens new window)