Vue 3 状态管理实战:用 Pinia 拆多 store、做持久化与调试
test12026-09-160 次阅读
为什么从 Vuex 切到 Pinia
Vue 3 项目里,Pinia 已经是官方推荐的状态方案。它去掉了 Vuex 里 mutations 这个冗余概念,state、getters、actions 直接对应,TypeScript 类型推断顺滑,store 之间是独立的模块,不需要用 namespace 层层嵌套。
一个最小可运行 store
下面用 setup 风格的 store 演示购物车场景:state 用 ref,派生数据用 computed,异步操作放 actions。
// stores/cart.ts
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useCartStore = defineStore("cart", () => {
const items = ref<{ id: number; name: string; price: number; qty: number }[]>([]);
const total = computed(() =>
items.value.reduce((sum, i) => sum + i.price * i.qty, 0)
);
function add(product: { id: number; name: string; price: number }) {
const found = items.value.find((i) => i.id === product.id);
if (found) found.qty += 1;
else items.value.push({ ...product, qty: 1 });
}
async function checkout() {
// 真实项目里这里发请求
await new Promise((r) => setTimeout(r, 300));
items.value = [];
}
return { items, total, add, checkout };
});
在组件里用
<script setup lang="ts">
import { useCartStore } from "./stores/cart";
const cart = useCartStore();
cart.add({ id: 1, name: "机械键盘", price: 399 });
</script>
<template>
<p>共 {{ cart.items.length }} 件,合计 {{ cart.total }} 元</p>
<button @click="cart.checkout()">结算</button>
</template>
按业务拆多个 store
- 用户态 user store、购物车 cart store、UI 状态 ui store 分开定义,互不耦合,哪个页面用到再引入哪个。
- 跨 store 调用很简单:在一个 store 的 action 里直接 import 另一个 store 的 useXxxStore() 即可,Pinia 自己管理实例化顺序。
持久化与调试
刷新后想保留购物车,用 pinia-plugin-persistedstate 一行配置即可写 localStorage,不需要自己监听 state 变化。
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
// store 里加一行开启
// export const useCartStore = defineStore("cart", () => { ... }, { persist: true });
调试时 Pinia 自带 devtools 支持,能直接看到每个 store 的状态变更时间线;开发环境建议给 action 加上 try/catch 并在失败时把错误抛到全局,方便定位是哪个 store 的动作出错。
T
test1
文章作者
为什么从 Vuex 切到 Pinia Vue 3 项目里,Pinia 已经是官方推荐的状态方案。它去掉了 Vuex 里...
- 分类
- 技术
- 发布时间
- 2026-09-16
- 字数
- 约 1982 字
- 阅读
- 0 次
