Pinia集中式状态(数据)管理
在面对数据管理时,我们先前仅仅是将其放在某个组件的脚本中,当别的组件需要使用时,再通过props的方法去传递数据使用,在涉及到一些对数据的操作时,还存在对响应式数据操作的考量等等。
而pinia作为一个集中式状态(数据)管理工具,它内置了丰富的数据管理包,通过pinia工具来存储数据,我们可以在组件中实现,即插即用,谁需要使用数据u
1.Pinia环境配置
首先,安装pinia依赖包,Vue3项目配置pinia需要加 @next
npm install pinia@next
接着,在main.js中配置使用pinia
import { createApp } from 'vue'
import App from './App.vue'
//引入Pinia
import { createPinia } from 'pinia'
//创建一个应用
const app = createApp(App)
//创建Pinia
const pinia = createPinia()
//安装使用Pinia
app.use(pinia)
//挂载整个应用
app.mount('#app')
这时,你的Vue3项目中已经成功引入并使用pinia
2.Pinia存储与读取数据
通常情况下,将使用Pinia工具的文件存储在@/store文件夹下,在此目录下创建js或ts文件来配置存储的数据
进入我们的文件中,首先引入pinia包中所需要的工具defineStore
import { defineStore } from "pinia";
然后写入存储数据的脚本,这些数据统一写在内置属性的state下,同时将其暴露出来
- 第一个参数:相当于为容器起一个名字。注意:这里的名字必须唯一,不能重复。
- 第二个参数:可以简单理解为一个配置对象,对容器仓库的配置说明
export const useCountStore = defineStore("count", {
//真正存储数据的地方
state(){
return {
sum:6
}
}
})
最后,在我们需要此数据的组件中引入此文件中的useCountStore即可进行读入数据
<template>
<div class="count">
<h2>当前求和为{{ countStore.sum }}</h2>
<select v-model.number="n">
<option v-for="num in 10" :key="num" :value="num">{{ num }}</option>
</select>
<button @click="SumCount">加法</button>
<button @click="SubCount">减法</button>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
//countStore是Proxy对象,可以拿到state中的数据
console.log("这是countStore", countStore);
console.log("这是state", countStore.$state);
//以下两种方式都可以拿到state中的数据
console.log("这是sum", countStore.$state.sum);
console.log("这是sum", countStore.sum);
let n = ref(1);
function SumCount() {
countStore.sum += n.value;
}
function SubCount() {
countStore.sum -= n.value;
}
</script>
3.三种数据修改方法
第一种:直接修改
const countStore = useCountStore();
function SumCount() {
//第一种修改方式
countStore.sum += n.value;
countStore.club = "LMG_Pro";
countStore.address = "山西孝义";
}
第二种:调用patch属性直接修改
这种方式不同于第一种对数据直接进行修改,这调用了Proxy对象中的patch属性,相当于借助pinia工具直接对数据进行修改,封装到patch中,在浏览器中只会被监听为一次事件,减少了浏览器缓存,适合在进行多种数据同时一次性发生修改时使用。
function SumCount() {
// 第二种修改方式
countStore.$patch({
sum: countStore.sum + n.value,
club: "LMG_Pro",
address: "山西孝义",
});
}
第三种:增加调用action中的动作(方法)
在配置的pinia工具的文件下,增加使用action选项:
import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
//actions里面放置一个个方法,用于响应动作
actions: {
increment(value) {
this.sum += value;
}
},
//真正存储数据的地方
state(){
return {
sum:6,
club:'LMG',
address:'山西太原'
}
}
})
在组件中便可直接调用此动作(方法):
function SumCount() {
// 第三种修改方式
countStore.increment(n.value);
}
优点:调用action中的动作,高内聚低耦合,适合异步操作,复用性强使用这种放到底层中的方法,模块化使用,若使用第一种,在面对大量数据操作的时候,很难维护
4.使用storeToRefs的解构赋值
概念:通过使用storeToRefs,我们可以接收pinia工具中存储的数据,并且将其合理的转换为响应式ref,方便在模板中使用
//获取pinia工具配置好的实例化对象
const countStore = useCountStore();
//使用解构赋值获得state中的数据
//这样获得的数据不是响应式的
// const { sum, club, address } = countStore;
//可使用toRefs转换为响应式
// 但这种方法会将pinia实例化对象中的全部属性均转换为ref响应式,对于前端组件来说是非常危险的, 而且性能较差
//const { sum, club, address } = toRefs(countStore);
//pinia工具考虑到了这种情况,可以使用storeToRefs:只会将state中的数据转换为ref响应式
const { sum, club, address } = storeToRefs(countStore);
注意:
pinia提供的storeToRefs只会将数据做转换,而'vue'的toRefs会转换store中数据
5.类似计算属性的getters
概念:当state中的数据,需要经过处理后再使用时,可以使用getters配置,这类似于计算属性computed,实际上它们的区别除了用法,似乎就是一个是Vue原生的办法,一个是在pinia下的数据计算属性办法
//类似计算属性的getter
getters: {
doubleSum(state) {
return state.sum * 2;
}
}
在
getters中定义的数据,也与在state中定义的数据使用方法类似,都能通过pinia的实例化对象直接调用,如:countStore.doubleSum
6.类似监视器的$subscribe
概念:通过store的$subscribe方法侦听state及其变化。当 store 中的状态发生变化时,会调用编写的回调函数。这对于需要在状态更新时执行某些操作(例如,记录日志、同步到本地存储等)非常有用。
myStore.$subscribe((mutation, state) => {
console.log('Mutation:', mutation);
console.log('New State:', state);
});
mutation 是 $subscribe 回调函数的第一个参数,表示 store 状态变化的描述信息。它通常包含了以下几个方面的内容:
- 类型 (type) : 描述状态变化的操作类型,如添加、修改、删除等。
- payload: 提供了与状态变化相关的数据。可以是改变的值或者与变化相关的上下文信息。
注意事项
性能: 频繁的状态变化可能会导致性能问题,因此应谨慎使用
$subscribe。建议仅在必要时进行状态监听。清理订阅: 在组件销毁时,如果不再需要监听,可以使用
$unsubscribe方法来移除订阅,防止内存泄漏。// 清理订阅 onBeforeUnmount(() => { unsubscribe(); });
7.配置store的组合式写法
与Vue3在setup语法糖中和hooks中的写法类似,就是将选项式改为组合式
这是一个选项式示例:
import { defineStore } from "pinia";
//选项式写法
export const useCountStore = defineStore("count", {
//actions里面放置一个个方法,用于响应动作
actions: {
increment(value) {
this.sum += value;
}
},
//真正存储数据的地方
state(){
return {
sum:6,
club:'LMG',
address:'山西太原'
}
},
//类似计算属性的getter
getters: {
doubleSum(state) {
return state.sum * 2;
}
}
}
这是一个组合式示例:
import { defineStore } from "pinia";
//组合式写法
import { ref, computed } from 'vue';
// 定义 store
export const useCountStore = defineStore("count", () => {
// 状态
const sum = ref(6);
const club = ref('LMG');
const address = ref('山西太原');
// 行为
const increment = (value) => {
sum.value += value;
};
// 计算属性
const doubleSum = computed(() => {
return sum.value * 2;
});
// 返回状态、行为和计算属性
return {
sum,
club,
address,
increment,
doubleSum
};
});