801 字
4 分鐘
告別 Vuex,擁抱 Pinia:Vue 狀態管理無痛轉型攻略

最近在升級專案從 Vue 2 到 Vue 3 的過程中,也將狀態管理從 Vuex 轉換到 Pinia。Pinia 是專為 Vue 3 設計的狀態管理庫,比 Vuex 更簡潔、更現代,能讓程式碼更易於維護。本文將比較 Vuex 和 Pinia 的差異,並提供一些遷移步驟與注意事項,幫助順利完成轉換,避免常見的問題。

Vuex vs. Pinia#

轉型前,先來看看 Pinia 到底贏在哪裡:

特性VuexPinia
API 簡潔度樣板程式碼多到爆,新手看了想哭直覺好懂,程式碼少一半,開發效率 UP!
Vue 3 整合Vue 2 時代產物,Vue 3 支援有點卡原生支援 Vue 3 Composition API,靈活度爆表
模塊化modules 雖然好用,但結構有點死板多個獨立 stores,結構自由,想怎麼拆就怎麼拆
TypeScriptTypeScript 支援… 嗯,有進步空間天生神力加持 TypeScript,型別安全有保障
開發體驗熱更新 (HMR)?好像有點問題…HMR 沒煩惱,開發體驗更上一層樓

1. 安裝 Pinia:新手村的第一步#

廢話不多說,先裝起來再說:

npm install pinia

yarn add pinia

2. 核心概念:創建 Pinia Stores#

Pinia 的 store 就像 Vuex 的 module,把 Vuex 的 modules 轉成 Pinia 的 stores 就對了。每個 store 裡面有 stategettersactions,概念很像,但寫法更簡潔。

// src/stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }), // 狀態
  getters: {
    doubleCount: (state) => state.count * 2, // 計算屬性
  },
  actions: {
    increment() {
      this.count++ // 修改狀態
    },
  },
})

3. 在組件中使用 Pinia:狀態輕鬆 Get#

在組件裡,用 useStore 函數把 store 抓進來,然後就可以直接用啦!

<script setup>
import { useCounterStore } from '@/stores/counter'

const counterStore = useCounterStore()
</script>

<template>
  <div>
    <p>Count: {{ counterStore.count }}</p>
    <p>Double Count: {{ counterStore.doubleCount }}</p>
    <button @click="counterStore.increment">Increment</button>
  </div>
</template>

4. 不用 <script setup> 也能玩 Pinia#

如果專案還在用舊版的 Options API,別擔心!Pinia 還是能陪你玩。用 mapState() 把 store 裡的東西映射到計算屬性,一樣可以在模板裡直接用。

<script>
import { mapState } from 'pinia'
import { useCounterStore } from '@/stores/counter'

export default {
  computed: {
    // 把 counterStore.count 映射成本地的 count
    ...mapState(useCounterStore, ['count']),

    // 把 counterStore.doubleCount 映射成本地的 doubled
    ...mapState(useCounterStore, {
      doubled: 'doubleCount',
    }),
  },
}
</script>

<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Doubled Count: {{ doubled }}</p>
  </div>
</template>

5. 組件外也要用 Store?沒問題!#

Pinia 的 store 实例是共享的,但在組件外使用時,例如:vue-router,記得先安裝 Pinia (app.use(pinia)),才能正確拿到 store。

import { createRouter } from 'vue-router'
import { useUserStore } from '@/stores/user'

const router = createRouter({ ... })

router.beforeEach((to) => {  
  const userStore = useUserStore() 
  if (to.meta.requiresAuth && !userStore.isLoggedIn) return '/login'
})

6. 結構大改造:Vuex 變 Pinia#

Vuex 愛用一個 store + 多個 modules,Pinia 則是鼓勵你用多個獨立的 stores,程式碼更乾淨俐落。

# Vuex 結構
src
└── store
    ├── index.js 
    └── modules
        ├── user.js
        └── cart.js

# Pinia 結構
src
└── stores
    ├── user.js
    └── cart.js

7. 轉型注意事項:避開地雷區#

  • 逐步替換:別一次轉換太多,慢慢來,比較快!
  • 命名空間:Pinia 的 store 預設就有命名空間,不用額外設定。
  • Composition API:Pinia 和 Composition API 是天生一對,好好利用更靈活!

如有內容任何問題,歡迎聯絡,會盡快回覆!

參考資料:

Pinia 官方文檔

Pinia - Vuex 的後繼者

告別 Vuex,擁抱 Pinia:Vue 狀態管理無痛轉型攻略
https://laplusda.com/posts/from-vuex-to-pinia/
作者
Zero
發佈於
2024-08-28
許可協議
CC BY-NC-SA 4.0