目录
在 Vue3 项目开发中,组件之间共享数据是一个很常见的问题。比如用户登录信息、购物车、主题设置,如果只依赖 props/emit,随着项目复杂度增加会变得十分混乱。
在 Vue2 时代,我们常用 Vuex 来解决这个问题。而在 Vue3 时代,Pinia 成为了更推荐的解决方案。
一、Pinia 是什么?
Pinia 是 Vue 官方团队推荐的 新一代状态管理工具,用来替代 Vuex。
它的优势非常明显:
-
更简单:没有 Vuex 的繁琐写法,直接上手
-
更轻量:体积小,性能好
-
TypeScript 友好:天然支持类型推导
-
与 Vue3 完美契合:基于组合式 API 设计
一句话:Pinia = Vue3 的官方状态管理库。
二、安装与初始化
安装 Pinia:
npm install pinia
在 main.ts
里挂载:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
三、创建一个 Store
在 src/stores/user.ts
中定义一个用户 Store:
import { defineStore } from 'pinia'
// defineStore(唯一ID, 配置对象)
export const useUserStore = defineStore('user', {
// state 类似于 data
state: () => ({
name: '张三',
age: 18,
token: ''
}),
// getters 类似于 computed
getters: {
isAdult: (state) => state.age >= 18
},
// actions 类似于 methods(可异步)
actions: {
setName(newName) {
this.name = newName
},
async login(username, password) {
return new Promise((resolve) => {
setTimeout(() => {
this.token = 'fake_token_123'
resolve(true)
}, 1000)
})
}
}
})
四、在组件中使用 Store
在 App.vue
中使用:
<script setup>
import { useUserStore } from './stores/user'
const userStore = useUserStore()
function changeName() {
userStore.setName('李四')
}
</script>
<template>
<div>
<h2>用户:{{ userStore.name }}</h2>
<h3>年龄:{{ userStore.age }}</h3>
<p>是否成年:{{ userStore.isAdult ? '是' : '否' }}</p>
<button @click="changeName">修改名字</button>
<button @click="userStore.login('admin', '123')">登录</button>
</div>
</template>
五、进阶用法
1. 模块化管理多个 Store
在大型项目里,通常会有多个 Store。我们可以在 stores/
文件夹下按功能拆分:
stores/
├── user.ts
├── cart.ts
└── settings.ts
例如购物车 Store cart.ts
:
import { defineStore } from 'pinia'
export const useCartStore = defineStore('cart', {
state: () => ({
items: []
}),
getters: {
totalPrice: (state) => state.items.reduce((sum, item) => sum + item.price, 0)
},
actions: {
addItem(item) {
this.items.push(item)
}
}
})
这样,在组件中只需要 useCartStore()
就能直接操作购物车数据。
2. Store 数据持久化
默认情况下,刷新页面后 Store 数据会丢失。
我们可以用 插件 实现持久化:
安装:
npm install pinia-plugin-persistedstate
在 main.ts
引入:
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
在 user.ts
中开启持久化:
export const useUserStore = defineStore('user', {
state: () => ({
token: ''
}),
actions: {
setToken(token) {
this.token = token
}
},
persist: true // 开启持久化
})
这样 token 就会自动存储在 localStorage 中,刷新不会丢失。
3. 热更新(HMR)
Pinia 支持热更新,适合开发过程中调试。
在 user.ts
中加上:
if (import.meta.hot) {
import.meta.hot.accept(acceptHMRUpdate(useUserStore, import.meta.hot))
}
这样修改 store 文件时,无需刷新页面即可应用更新。
六、Pinia vs Vuex 对比
对比点 | Vuex | Pinia |
---|---|---|
学习成本 | 高 | 低 |
写法 | mutations + actions | 直接 actions |
类型支持 | 一般 | 原生友好 |
体积 | 偏大 | 更轻量 |
Vue3 适配 | 一般 | 完美 |
七、总结
Pinia 的设计哲学就是:让状态管理变得简单自然。
-
对于小项目,Pinia 上手快,几乎没学习成本;
-
对于大项目,Pinia 提供了模块化、插件、持久化等功能,完全够用;
-
对于开发体验,它比 Vuex 更轻量,TS 支持更佳。
所以在 Vue3 项目中,推荐直接使用 Pinia,而不是 Vuex。