Vue 3 + Pinia 状态管理最佳实践:从零实现一个高效的全局状态管理方案
在 Vue 3 项目中,状态管理是核心之一,合理的状态管理方案可以大幅提升项目的可维护性、可读性以及性能。过去,我们在 Vue 2 时代主要使用 Vuex,但 Vue 3 之后,Pinia 逐渐成为更优的选择。本篇文章将深入探讨 Pinia 的使用方式,并结合 Vue 3 + Vite 进行实战演示。
1. 为什么选择 Pinia?
Pinia 是 Vue 官方推荐的状态管理库,它相较于 Vuex 具有以下优势:
✅ 简单易用:API 设计更符合 Vue 3 组合式 API。
✅ 类型安全:完美支持 TypeScript,并提供类型推导。
✅ 更轻量:没有复杂的 mutations,只使用 actions 和 state。
✅ Vue Devtools 支持:可以在 Vue Devtools 里查看状态变化。
2. 在 Vue 3 项目中集成 Pinia
2.1 初始化 Vue 3 + Vite 项目
我们使用 create-vite
快速搭建 Vue 3 项目:
npm create vite@latest my-vue-app --template vue
cd my-vue-app
npm install
安装 Pinia:
npm install pinia
2.2 在 Vue 项目中注册 Pinia
在 main.js
中注册 Pinia:
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
const app = createApp(App);
app.use(createPinia());
app.mount("#app");
3. 使用 Pinia 管理全局状态
3.1 创建一个 store
在 src/stores/
目录下新建 userStore.js
:
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({
name: "Alice",
age: 25,
isLoggedIn: false,
}),
getters: {
userInfo: (state) => `${state.name} (${state.age}岁)`,
},
actions: {
login(name) {
this.name = name;
this.isLoggedIn = true;
},
logout() {
this.name = "";
this.isLoggedIn = false;
},
},
});
说明:
state
:存储全局状态。getters
:类似于 Vuex 的getters
,用来计算衍生状态。actions
:类似于 Vuex 的mutations + actions
,可以直接修改state
,并且可以是异步的。
4. 在 Vue 组件中使用 Pinia
4.1 在 App.vue
中使用
<script setup>
import { useUserStore } from "./stores/userStore";
const userStore = useUserStore();
function handleLogin() {
userStore.login("Bob");
}
function handleLogout() {
userStore.logout();
}
</script>
<template>
<div>
<h1>当前用户: {{ userStore.userInfo }}</h1>
<button @click="handleLogin">登录</button>
<button @click="handleLogout">退出</button>
</div>
</template>
说明:
- 直接使用
userStore.userInfo
获取计算属性。 - 通过
handleLogin
和handleLogout
触发actions
来修改状态。
5. Pinia 的高级用法
5.1 组合式 API
Pinia 也支持 setup()
形式:
import { defineStore } from "pinia";
import { ref, computed } from "vue";
export const useCartStore = defineStore("cart", () => {
const items = ref([]);
const totalItems = computed(() => items.value.length);
function addItem(item) {
items.value.push(item);
}
function removeItem(index) {
items.value.splice(index, 1);
}
return { items, totalItems, addItem, removeItem };
});
5.2 在 Vue 组件中使用
<script setup>
import { useCartStore } from "./stores/cartStore";
const cartStore = useCartStore();
function addNewItem() {
cartStore.addItem({ id: 1, name: "商品 A", price: 100 });
}
function removeFirstItem() {
cartStore.removeItem(0);
}
</script>
<template>
<div>
<h2>购物车 ({{ cartStore.totalItems }} 件商品)</h2>
<button @click="addNewItem">添加商品</button>
<button @click="removeFirstItem">移除第一件商品</button>
</div>
</template>
6. 持久化存储 Pinia 状态
默认情况下,Pinia 的状态刷新页面会丢失。我们可以使用 pinia-plugin-persistedstate
来实现持久化存储:
npm install pinia-plugin-persistedstate
在 main.js
配置:
import { createApp } from "vue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
import App from "./App.vue";
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
const app = createApp(App);
app.use(pinia);
app.mount("#app");
然后,在 userStore.js
里启用持久化:
export const useUserStore = defineStore("user", {
state: () => ({
name: "Alice",
age: 25,
isLoggedIn: false,
}),
persist: true, // 开启本地存储
});
这样,Pinia 状态会自动存储在 localStorage 中,刷新页面不会丢失。
7. Pinia vs Vuex 选哪个?
特性 | Pinia | Vuex |
---|---|---|
语法风格 | 组合式 API / 选项式 API | 选项式 API |
类型安全 | ✅ 内置支持 | ❌ 需手动定义类型 |
开发体验 | ✅ 更简单,代码更少 | ❌ 需要定义 mutations 、actions |
异步操作 | ✅ actions 内部直接支持 | ✅ 需使用 actions |
状态持久化 | ✅ 支持 persist 插件 | ❌ 需手动使用 vuex-persist |
适用项目 | 适用于 Vue 3 新项目 | 适用于 Vue 2 旧项目 |
总结
✅ Pinia 更现代化,比 Vuex 轻量、简洁、易维护。
✅ 支持 TypeScript 和 Vue 3 组合式 API,适用于新项目。
✅ 持久化存储更简单,无需复杂插件。
✅ 开发体验优秀,代码更清晰,避免 Vuex 冗余代码。
如果你的项目使用 Vue 3,Pinia 是目前最佳的状态管理方案,值得学习和使用!🔥🚀