Pinia 和 Vuex 的区别?为什么 Vue3 推荐用 Pinia?
Pinia 基本用法
// stores/counter.js
import { defineStore } from 'pinia'
// 组合式写法(推荐)
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const double = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, double, increment }
})// 组件中使用
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
console.log(counter.count)
counter.increment()
// 解构需要 storeToRefs 保持响应式
import { storeToRefs } from 'pinia'
const { count, double } = storeToRefs(counter)
const { increment } = counter // 方法不需要 storeToRefsPinia vs Vuex
| 特性 | Vuex 4 | Pinia |
|---|---|---|
| 模块 | 需要 modules 嵌套 | 每个 store 独立平级 |
| Mutations | 需要(修改状态) | ❌ 不需要,直接修改 |
| TypeScript | 支持差 | 优秀(类型自动推断) |
| Composition API | 有限支持 | 原生支持 |
| 体积 | 较大 | ~1KB |
| 开发者工具 | 支持 | 支持(更好) |
| 学习成本 | 中 | 低 |
| SSR | 复杂 | 简单 |
为什么不用 Mutations
Vuex 要求通过 mutations 修改状态,因为要配合 devtools 追踪:
// Vuex
mutations: {
SET_COUNT(state, payload) { state.count = payload }
}
actions: {
increment({ commit }) { commit('SET_COUNT', count + 1) }
}
// Pinia:直接修改
const increment = () => { count.value++ }
// Pinia 仍然可以被 devtools 追踪Pinia 的 Store 模块化
// 每个文件一个 store,不需要 modules
// stores/user.js
export const useUserStore = defineStore('user', () => { ... })
// stores/cart.js
export const useCartStore = defineStore('cart', () => { ... })
// stores/settings.js
export const useSettingsStore = defineStore('settings', () => { ... })
// 互相调用
const userStore = useUserStore()
const cartStore = useCartStore()异步操作
export const useUserStore = defineStore('user', () => {
const user = ref(null)
const loading = ref(false)
async function fetchUser(id) {
loading.value = true
try {
user.value = await api.getUser(id)
} finally {
loading.value = false
}
}
return { user, loading, fetchUser }
})持久化
import { persist } from 'pinia-plugin-persistedstate'
export const useUserStore = defineStore('user', () => {
// ...
}, {
persist: true // 自动同步到 localStorage
})总结
- Pinia 是 Vue3 官方推荐的状态管理库
- 更简洁、更好的 TS 支持、更小的体积
- 如果项目从 Vuex 迁移,可以逐步迁移(Pinia 和 Vuex 可以共存)