Skip to content

Pinia —— 符合直觉的 Vue.js 状态管理库

引入Pinia库

main.ts中引入 pinia库并使用

javascript
import { createPinia } from 'pinia'

app.use(createPinia())

创建 Store

@/store/目录下创建 backpack.ts文件

typescript
import { defineStore } from 'pinia'
import { reactive } from 'vue'

export const useBackPackStore = defineStore('BackPack', {
  state() {
    return {
      items: reactive([
        // 背包中的物品
        { id: '001', name: '绷带', number: 16 },
        { id: '002', name: '饮料', number: 5 },
        { id: '003', name: '药丸', number: 2 },
        { id: '004', name: '面包', number: 6 },
        { id: '005', name: '子弹', number: 50 },
      ]),
      capacity: 100, // 背包容量
      weight: 50, // 背包重量
    }
  },
})

使用 Store

在组件中使用 store

vue
<template>
  <h3 v-if="items.length == 0">您的背包空空如也...</h3>
  <ul v-else>
    <li>
      <span class="name title">物品</span>
      <span class="number title">数量</span>
    </li>
    <li v-for="goods in items" :key="goods.id">
      <span class="name">{{ goods.name }}</span>
      <span class="number">{{ goods.number }}</span>
    </li>
    <span>背包容量:{{ capacity }}</span><span>背包当前重量:{{ weight }}</span>
  </ul>
</template>

<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useBackPackStore } from '@/stores/backpack';
const BackPackStore = useBackPackStore();

// 解构
const { items, capacity, weight } = storeToRefs(BackPackStore);
</script>

注意,我们使用了一个 pinia提供的API:storeToRefs来解构 store,通过这种方式解构的数据是响应式的。

修改 Store中的数据

方式一:直接修改

vue
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useBackPackStore } from '@/stores/backpack';
const BackPackStore = useBackPackStore();

// 解构
const { items, capacity, weight } = storeToRefs(BackPackStore);

// 修改store中的数据

// 直接修改
capacity = 200;
weight = 3;

</script>

方式二、$patch批量修改

vue
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useBackPackStore } from '@/stores/backpack';
const BackPackStore = useBackPackStore();

// 解构
const { items, capacity, weight } = storeToRefs(BackPackStore);

// 修改store中的数据

// 使用$patch批量修改
BackPackStore.$patch({
  capacity: 200,
  weight: 3
})

</script>

方式三、使用actions修改数据

想要使用 actions修改数据,需要先在 store中定义 actions

typescript
export const useBackPackStore = defineStore('BackPack', {
  state() {
    return {
      items: reactive([
        // 背包中的物品
        { id: '001', name: '绷带', number: 16 },
        { id: '002', name: '饮料', number: 5 },
        { id: '003', name: '药丸', number: 2 },
        { id: '004', name: '面包', number: 6 },
        { id: '005', name: '子弹', number: 50 },
      ]),
      capacity: 100, // 背包容量
      weight: 50, // 背包重量
    }
  },
  actions: {
    increment(value: { capacity: number; weight: number }) {
      this.capacity = value.capacity
      this.weight = value.weight
    },
  },
})
vue
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useBackPackStore } from '@/stores/backpack';
const BackPackStore = useBackPackStore();

// 解构
const { items, capacity, weight } = storeToRefs(BackPackStore);

// 修改store中的数据

// 方式三、通过action修改
BackPackStore.increment({
  capacity: 200,
  weight: 3
})
</script>

函数式的 Store

piniadefineStore的第二个参数可以写成组合式的,不过要记得将需要用到的东西返回出去

typescript
import { defineStore } from 'pinia'
import { reactive } from 'vue'

export const useBackPackStore = defineStore('BackPack', () => {
  const items = reactive([
    // 背包中的物品
    { id: '001', name: '绷带', number: 16 },
    { id: '002', name: '饮料', number: 5 },
    { id: '003', name: '药丸', number: 2 },
    { id: '004', name: '面包', number: 6 },
    { id: '005', name: '子弹', number: 50 },
  ])
  let capacity = 100 // 背包容量
  let weight = 50 // 背包重量

  function increment(value: { capacity: number; weight: number }) {
    capacity = value.capacity
    weight = value.weight
  }

  return {
    items,
    capacity,
    weight,
    increment,
  }
})

$subscribe监听state数据变化

可以通过 store$subscribe() 方法侦听 state 及其变化。比起普通的 watch(),使用 $subscribe() 的好处是 subscriptionspatch 后只触发一次

vue
<script setup lang="ts">
import { storeToRefs } from 'pinia';
import { useBackPackStore } from '@/stores/backpack';
const BackPackStore = useBackPackStore();

// 解构
const { items, capacity, weight } = storeToRefs(BackPackStore);

// 修改store中的数据

// 方式三、通过action修改
BackPackStore.increment({
  capacity: 200,
  weight: 3
})

BackPackStore.$subscribe((v1, v2) => {
  console.log(v1, '@@', v2)
})

</script>

$subscribe()接收的第一个参数:

$subscribe()接收的第二个参数:

向State中添加新数据

javascript
// 向store中添加新的响应式数据
const obj = reactive({
	totalPrice: 28391,
	totalNumbers: 201
});
// 将obj对象中的属性合并到store中
Object.assign(store, obj);

注意:不推荐使用这样方式向state中直接添加新属性,虽然具有响应性,但是控制台工具会检测不到。