Vuex vs Pinia 差異比較
比較 Vuex 和 Pinia 的核心差異,包含 API 設計、TypeScript 支援、模組化方式等,並提供遷移指南。
1. 面試回答主軸
- 核心差異:Vuex 需要 mutations,Pinia 不需要;Pinia 有更好的 TypeScript 支援;模組化方式不同。
- 選擇建議:Vue 3 新專案推薦 Pinia,Vue 2 專案使用 Vuex。
- 遷移考量:從 Vuex 遷移到 Pinia 的步驟與注意事項。
2. 核心差異總覽
| 特性 | Vuex | Pinia |
|---|---|---|
| Vue 版本 | Vue 2 | Vue 3 |
| API 複雜度 | 較複雜(需要 mutations) | 更簡潔(不需要 mutations) |
| TypeScript 支援 | 需要額外配置 | 原生完整支援 |
| 模組化 | 嵌套模組 | 扁平化,每個 store 獨立 |
| 體積 | 較大 | 更小(約 1KB) |
| 開發體驗 | 良好 | 更好(HMR、Devtools) |
3. API 差異比較
3.1 Mutations vs Actions
Vuex:需要 mutations 來同步修改 state
// Vuex
export default createStore({
state: { count: 0 },
mutations: {
INCREMENT(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('INCREMENT');
},
},
});
Pinia:不需要 mutations,直接在 actions 中修改 state
// Pinia
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++; // 直接修改
},
},
});
關鍵差異:
- Vuex:必須透過
mutations同步修改 state,actions透過commit調用mutations - Pinia:不需要
mutations,actions可以直接修改 state(同步或非同步都可以)
3.2 State 定義
Vuex:state 可以是物件或函數
state: {
count: 0,
}
Pinia:state 必須是函數,避免多實例共享狀態
state: () => ({
count: 0,
})
3.3 Getters
Vuex:getters 接收 (state, getters) 作為參數
getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne: (state, getters) => getters.doubleCount + 1,
}
Pinia:getters 可以使用 this 訪問其他 getters
getters: {
doubleCount: (state) => state.count * 2,
doubleCountPlusOne(): number {
return this.doubleCount + 1;
},
}
3.4 在組件 中使用
Vuex:使用 mapState、mapGetters、mapActions 輔助函數
computed: {
...mapState(['count']),
...mapGetters(['doubleCount']),
},
methods: {
...mapActions(['increment']),
}
Pinia:直接使用 store 實例,使用 storeToRefs 保持響應性
const store = useCounterStore();
const { count, doubleCount } = storeToRefs(store);
const { increment } = store;
4. 模組化差異
4.1 Vuex Modules(嵌套模組)
Vuex:使用嵌套模組,需要 namespaced: true
// stores/user.js
export default {
namespaced: true,
state: { name: 'John' },
mutations: {
SET_NAME(state, name) {
state.name = name;
},
},
};
// 在組件中使用
this.$store.dispatch('user/SET_NAME', 'Jane'); // 需要命名空間前綴
4.2 Pinia Stores(扁平化)
Pinia:每個 store 都是獨立的,無需嵌套
// stores/user.ts
export const useUserStore = defineStore('user', {
state: () => ({ name: 'John' }),
actions: {
setName(name: string) {
this.name = name;
},
},
});
// 在組件中使用
const userStore = useUserStore();
userStore.setName('Jane'); // 直接調用,無需命名空間
關鍵差異:
- Vuex:需要嵌套模組,使用
namespaced: true,調用時需要命名空間前綴 - Pinia:每個 store 獨立,無需命名空間,直接調用