Pinia的基本使用

755 阅读1分钟

与Vuex的区别

  1. vuex的同步操作用mutatuins,异步操作用actions,太麻烦
  2. pinia没有mutations,同步异步都用actions
  3. 版本问题
    • vuex的最新版本4.x
      • vuex4用于vue3
      • vuex3用于vue2
    • pinia最新版本2.x
      • 既支持vue2也支持vue3
  4. pinia没有命名空间模块
  5. pinia更好的支持ts

基本使用

pinia的核心配置

  • state
  • actions 同步异步都支持
  • getters

安装pinia

npm i pinia

使用pinia

// main.ts
import { createApp } from 'vue'
import {createPinia} from "pinia

// 创建pinia实例
const pinia = createPinia()

createApp(App).use(pinia).mount('#app')

image.png

// store/index.ts
import { defineStore } from 'pinia'

interface IState {
  count: number
  name: string
  isAdmin: boolean
  items: Array<any>
  info: {
    age: number
  }
}

/**
 * @desc
 * 定义并导出容器
 * 参数一:容器的 ID,必须唯一,pinia会把所有容器挂载到跟容器上
 * 参数二:配置选项
 * 返回值:一个函数,调用后返回容器实例
 */
export const useMainStore = defineStore('main', {
  /**
   * @desc
   * 1. state是一个返回初始状态的函数
   * 2. 推荐使用箭头函数,为了更好的TS类型推断
   */
  state: (): IState => ({
    // 所有这些属性都将自动推断出它们的类型
    count: 0,
    name: 'Eduardo',
    isAdmin: true,
    items: [],
    info: {
      age: 18
    }
  }),
})

在组件中获取 state 中的状态

// Demo.vue
<template>
    <h1>Pinia</h1>
    <!-- 在模板中使用 -->
    mainStore.count : {{ mainStore.count }}
    <!-- 解构获取store中的状态 -->
    count : {{ count }} name : {{ name }}
    <br />
    info:{{ info }}
    <br />
    <button @click="mainStore.info.age++">按钮</button>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { useMainStore } from "./store/index";
export default defineComponent({
  setup() {
    // 获取容器实例
    const mainStore = useMainStore()
    // 获取store中的状态
     console.log(mainStore.count); // 0
    // 解构获取store中的状态
    //#region
    // 对于基本数据类型的解构的错误写法
    // const { count, name } = mainStore;
    // 因为 proxy 只能代理引用类型数据
    // {
    //     count: 0,
    //     name: 'Eduardo',
    //     isAdmin: true,
    // }
    // proxy 代理了整个对象,而对于对象里面的基本数据类型并不能代理,所以解构出来的基本数据类型不是响应式的
    //#endregion
    // 1. 解构基本数据类型
    const { count, name } = storeToRefs(mainStore);
    console.log(count.value); // 0
    // 2. 解构对象类型
    // 写法一
    const { info } = storeToRefs(mainStore);
    // 写法二
    // const { info } = mainStore; // info是引用数据类型,被递归代理proxy
    return { mainStore, count, name, info };
  },
});
</script>

修改state中的状态

<script lang="ts">
import { defineComponent } from "vue";
import { useMainStore } from "./store/index";
import { storeToRefs } from "pinia";
export default defineComponent({
  setup() {
      const mainStore = useMainStore();
      const { count, name, info } = storeToRefs(mainStore);
      // 修改store中的状态
      const handleStore = () => {
      // 单个修改
      mainStore.count = 10;
      // 批量修改
      // 写法一 $patch函数的参数为对象,有内部优化
      mainStore.$patch({
        count: 10,
        name: "jack Chen",
        items: [...mainStore.items, 3],
      });
      // 写法二 $patch函数的参数为回调函数
      mainStore.$patch((state) => {
        state.count = 10;
        state.name = "jack Chen";
        state.items.push(3);
      });
      // 逻辑比较多时,使用actions修改
      mainStore.changeState({ num: 10 });
    };
    return { mainStore, count, name, info };
  },
});
</script>
// store/index.ts
import { defineStore } from 'pinia'

interface IState {
  count: number
  name: string
  isAdmin: boolean
  items: Array<any>
  info: {
    age: number
  }
}

export const useMainStore = defineStore('main', {
  state: (): IState => ({
    // 所有这些属性都将自动推断出它们的类型
    count: 0,
    name: 'Eduardo',
    isAdmin: true,
    items: [1, 2],
    info: {
      age: 18
    }
  }),
  actions: {
    // 不能使用箭头函数定义changeState
    changeState<T extends { num: number }> (payload: T) {
      // 单个修改
      this.count = payload.num
      // 批量修改
      //   this.$patch({})
      this.$patch(state => {
        state.name = 'jack Chen'
        state.items.push(4)
      })
    }
  }
})