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

借助storeToRefsstore中的数据转为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);
});
posted @ 2024-04-15 17:47  songxia777  阅读(30)  评论(0编辑  收藏  举报