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 // 方法不需要 storeToRefs

Pinia 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
})

总结

同分类其他题目