深入浅出Pinia---集中式状态(数据)管理

238 阅读3分钟

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文件夹下,在此目录下创建jsts文件来配置存储的数据

进入我们的文件中,首先引入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 状态变化的描述信息。它通常包含了以下几个方面的内容:

  1. 类型 (type) : 描述状态变化的操作类型,如添加、修改、删除等。
  2. payload: 提供了与状态变化相关的数据。可以是改变的值或者与变化相关的上下文信息。

注意事项

  1. 性能: 频繁的状态变化可能会导致性能问题,因此应谨慎使用 $subscribe。建议仅在必要时进行状态监听。

  2. 清理订阅: 在组件销毁时,如果不再需要监听,可以使用 $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
     };
 });