04 Pinia 数据状态管理
简介
pinia 和 vuex 具有相同的功效, 是 Vue 的存储库,允许跨组件/页面共享状态
设计使用的是 Composition api,更符合vue3的设计思维
Pinia 对 Vue 2 和 Vue 3 都有效,并且不需要您使用组合 AP
可以理解为 一种集中式状态(数据)管理
Store
是一个保存:状态、业务逻辑 的实体,每个组件都可以读取、写入它
它有三个概念:state、getter、action
,相当于组件中的: data、 computed 和 methods
搭建 Pinia
环境
安装
npm install pinia
配置 main.ts
文件
import { createApp } from 'vue';
// 1. 引入createPinia,用于创建pinia
import { createPinia } from 'pinia';
import App from './App.vue';
// 2. 创建pinia
const app = createApp(App);
// 3. 使用插件
app.use(createPinia());
app.mount('#app');
一个简单的案例规范
1. 在目录 stores
里面创建一个 count.ts
对象,存储 count模块相关的store对象
import { ref } from 'vue';
// 1. 引入defineStore用于创建store
import { defineStore } from 'pinia';
// 向外暴露一个 useXXXStore store对象,命名规则采用Hooks的方式
export const useCountStore = defineStore('count', {
// 数据状态管理
state() {
return {
sum: ref(1),
name:'张三'
};
},
// getters数据管理
getters: {
doubleSum(): number {
return this.sum * 2;
},
},
// 方法管理
actions: {
add() {
this.sum += 1;
},
},
});
也可以使用下面的函数的方式--即组合式语法
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCountStore = defineStore('count', () => {
const sum = ref(0);
function add() {
sum.value++;
}
let bigSum = computed(() => {
return sum.value * 2;
});
return { sum, add, bigSum };
});
2. 组件使用 store 对象
<template>
<!-- 使用state数据 -->
<h1>当前加1后的数值:{{ countStore.sum }}</h1>
<!-- 使用getters数据 -->
<h1>数值的2倍:{{ countStore.doubleSum }}</h1>
<!-- 使用自定义actions方法 -->
<button @click="countStore.add">点我加1</button>
<hr />
</template>
<script lang="ts" setup>
// 1. 引用对应模块的store对象
import { useCountStore } from '@/stores/count';
// 2. 调用useCountStore得到模块的store对象
const countStore = useCountStore();
</script>
3. 在组件中, 修改store数据的3种方法
第一种修改方式,直接修改
countStore.sum = 666
第二种修改方式:批量修改 $patch
countStore.$patch({
sum:999,
name:'李四'
})
第三种修改方式:借助action修改(action中可以编写一些业务逻辑)
import { 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
即可
<script lang="ts" setup>
// 1. 引用对应模块的store对象
import { useCountStore } from '@/stores/count';
// 2. 调用useCountStore得到模块的store对象
const countStore = useCountStore();
// 调用对应action
countStore.incrementOdd(n.value);
</script>
4. getters
概念:当state
中的数据,需要经过处理后再使用时,可以使用getters
配置。
import { ref } from 'vue';
// 1. 引入defineStore用于创建store
import { defineStore } from 'pinia';
export const useCountStore = defineStore('count', {
// 数据状态管理
state() {
return {
msg: 'hello',
};
},
// getters数据管理
getters: {
// 写法一:变大写 使用this ,必须指定返回类型
upperCaseMsg(): string {
return this.msg.toUpperCase();
},
// 写法二state:变大写,箭头函数
upperCaseMsg2: (state) => {
return state.msg.toUpperCase();
},
// 写法二state:变大写
upperCaseMsg3(state) {
return state.msg.toUpperCase();
},
},
});
组件中读取数据:
const { increment, decrement } = countStore;
// 直接获取即可 storeToRefs使数据保持响应式
let { sum, school, bigSum, upperSchool } = storeToRefs(countStore);
storeToRefs
借助storeToRefs
将store中的数据转为ref对象,方便在模板中使用
pinia提供的storeToRefs只会将store中的数据做转换,而Vue的toRefs会转换store中的所有数据,包括方法等
<template>
<div class="count">
<h2>当前求和为:{{ sum }}</h2>
</div>
</template>
<script setup lang="ts" name="Count">
// 1. 引用对应模块的store对象
import { useCountStore } from '@/stores/count';
// 引入 storeToRefs
import { storeToRefs } from 'pinia';
// 2. 调用useCountStore得到模块的store对象
const countStore = useCountStore();
// 使用storeToRefs转换countStore,随后解构出来的数据依然保持响应式
const { sum } = storeToRefs(countStore);
</script>
$subscribe 订阅---侦听 state
及其变化
通过 store 的 $subscribe()
方法侦听 state
及其变化
countStore.$subscribe((mutate, state) => {
console.log(mutate);
console.log(state);
});