Vue3:状态管理 Pinia

Vue3 专属状态管理工具。

官方文档:https://pinia.vuejs.org/


挂载 Pinia

  1. src/main.js 中导入并挂载 pinia。
import { createPinia } from "pinia";

app.use(createPinia());
  1. 创建 src/store 文件夹,并区分模块创建 .js 文件,并配置页面的状态管理。

store id 可以写在 defineStore() 的参数一,也可以写在对象里。


state

pinia 中的 store 是模块化的,根据不同的状态划分不同的模块。

  1. 创建 src/store/productStore.js 文件。
# 写法一
import { defineStore } from "pinia";

export const useProductStore = defineStore("ProductStore", {
    // state 函数用于返回状态对象(数据)
    state: () => {
        return {
            products: [],
        };
    },
    ...
});
  1. 页面引入

直接从 store 对象中将状态解构出来,会失去响应式,状态发送变化不会驱动视图更新,storeToRefs 可以将这些数据转为响应式。


# actions > `actions` 相当于组件中的方法,它们可以使用 `defineStore()` 中的 `actions` 属性进行定义,并且非常适合定义业务逻辑。
# src/store/productStore.js

import { defineStore } from "pinia";

export const useProductStore = defineStore("ProductStore", {
    // state 函数用于返回状态对象(数据)
    state: () => {
        return {
            products: [],
        };
    },
    // 既可以执行异步操作,也可以修改状态
    actions: {
        // 导入数据
        async fill () {
            // 异步加载模块
            this.products = await (import("@/data/products.json").default);
        },
        // 修改金额
        updateProductItemPrice(index) {
            this.products[index].price += 1;
        },
    },
});
# src/store/cartStore.js

import { defineStore } from "pinia";

export const useCartStore = defineStore("cartStore", {
    state: () => {
        return {
            // 购物车数据
            items: [],
        };
    },
    actions: {
        // 点击事件:加入购物车
        addItems(count, product) {
            for(let i=0; i<count, i++) {
                this.items.push(product);
            };
        },
    },
});
<!-- App.vue -->

<script setup>
import { storeToRefs } from "pinia";
import { onMounted } from "vue";
import { useProductStore } from "./store/productStore.js";
import { useCartStore } from "./store/cartStore.js";

const productStore = useProductStore();
const { products } = storeToRefs(productStore);

const cartStore = useCartStore();
    
onMounted(() => {
    // 页面加载完成,渲染数据
    productStore.fill();
});

// 点击加入购物车
const addCart = (count, product) => {
    cartStore.addItems(count, product)
}
</script>

<template>
	<ul class="sm:flex flex-wrap lg:flex-nowrap gap-5">
		<ProductCard v-for="product in products" :key="product.name"
			:product="product"
			@addToCart="addToCart($event, product)"
		/>
    </ul>
</template>

getters

getters 完全等同于 Store 状态的计算值。可以使用 defineStore() 中的 getters 属性定义。接受 state 作为第一参数,推荐使用箭头函数,当使用箭头函数时 this 指向为 undefined

# src/store/cartStore.js

import { defineStore } from "pinia";
	
export const useCartStore = defineStore("cartStore", {
    state: () => {
        return {
            // 购物车数据
            items: [],
        };
    },
    actions: {
        // 点击事件:加入购物车
        addItems(count, product) {
            for(let i=0; i<count, i++) {
                this.items.push(product);
            };
        },
    },
    getters: {
        // 计算购物车的数量
        count: (state) => state.items.length,
    },
});
<!-- src/components/CartWidget.vue -->

<span class="cursor-pointer" @click="active = true">
    <fa icon="shopping-cart" size="lg" class="text-gray-700" />
    <div class="cart-count absolute">{{ cartStore.count }}</div>
</span>

plugins

由于有了底层 API 的支持,Pinia store 现在完全支持扩展。以下是你可以扩展的内容:

  • 为 store 添加新的属性
  • 定义 store 时增加新的选项
  • 为 store 增加新的方法
  • 包装现有的方法
  • 改变甚至取消 action
  • 实现副作用,如本地存储
  • 仅应用插件于特定 store

插件是通过 pinia.use() 添加到 pinia 实例的。最简单的例子是通过返回一个对象将一个静态属性添加到所有 store。

import { createPinia } from 'pinia'

// 在安装此插件后创建的每个 store 中都会添加一个名为 `secret` 的属性。
// 插件可以保存在不同的文件中
function SecretPiniaPlugin() {
  return { secret: 'the cake is a lie' }
}

const pinia = createPinia()
// 将该插件交给 Pinia
pinia.use(SecretPiniaPlugin)

// 在另一个文件中
const store = useStore()
store.secret // 'the cake is a lie'

这对添加全局对象很有用,如路由器、modal 或 toast 管理器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤安先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值