Pinia 最佳實踐與常見錯誤
在多品牌平台專案中,Pinia Store 的最佳實踐與常見錯誤處理。
1. 面試回答主軸
- 設計原則:單一職責原則、保持 Store 精簡、避免在 Store 中直接調用 API。
- 常見錯誤:直接解構失去響應性、在 Setup 外部調用 Store、修改 State 破壞響應性、循環依賴。
- 最佳實踐:使用 TypeScript、職責分離、在 Composable 中組合多個 Store。
2. Store 設計原則
2.1 單一職責原則
// ✅ 好的設計:每個 Store 只負責一個領域
useAuthStore(); // 只管認證
useUserInfoStore(); // 只管用戶資訊
useGameStore(); // 只管遊戲資訊
// ❌ 壞的設計:一個 Store 管理所有東西
useAppStore(); // 管理認證、用戶、遊戲、設定...
2.2 保持 Store 精簡
// ✅ 推薦
export const useBannerStore = defineStore('bannerStore', () => {
const bannerState = reactive({ list: [] });
function setStoreBannerList(list: Response.BannerList) {
bannerState.list = list;
}
return { bannerState, setStoreBannerList };
});
// ❌ 不推薦 :Store 中包含複雜的業務邏輯
// 應該放在 composable 中
2.3 避免在 Store 中直接調用 API
// ❌ 不推薦:在 Store 中直接調用 API
export const useGameStore = defineStore('gameStore', {
actions: {
async fetchGames() {
const data = await api.getGames(); // API 調用
this.list = data;
},
},
});
// ✅ 推薦:在 Composable 中調用 API,Store 只負責存儲
export const useGameStore = defineStore('gameStore', {
actions: {
setGameList(list: Game[]) {
this.list = list;
},
},
});
export function useGame() {
const gameStore = useGameStore();
async function fetchGames() {
const { status, data } = await api.getGames(); // Composable 中調用 API
if (status) {
gameStore.setGameList(data); // Store 只負責存儲
}
}
return { fetchGames };
}
3. 使用 TypeScript
// ✅ 完整的型別定義
type UserState = {
info: Response.UserInfo;
walletList: Response.UserWalletList;
};
export const useUserInfoStore = defineStore('useInfoStore', () => {
const state = reactive<UserState>({
info: {} as Response.UserInfo,
walletList: [],
});
return { state };
});
4. 常見錯誤
4.1 錯誤 1:直接解構導致響應性丟失
// ❌ 錯誤
const { count } = useCounterStore();
count; // 不是響應式的
// ✅ 正確
const { count } = storeToRefs(useCounterStore());
count.value; // 響應式的
4.2 錯誤 2:在 Setup 外部調用 Store
// ❌ 錯誤:在模組頂層調用
const authStore = useAuthStore(); // ❌ 錯誤時機
export function useAuth() {
return {
isLogin: authStore.isLogin,
};
}
// ✅ 正確:在函數內部調用
export function useAuth() {
const authStore = useAuthStore(); // ✅ 正確時機
return {
isLogin: authStore.isLogin,
};
}
4.3 錯誤 3:修改 State 時破壞響應性
// ❌ 錯誤:直接賦值新陣列
function updateList(newList) {
gameState.list = newList; // 可能失去響應性
}
// ✅ 正確:使用 splice 或 push
function updateList(newList) {
gameState.list.length = 0;
gameState.list.push(...newList);
}
// ✅ 也可以使用 reactive 的賦值
function updateList(newList) {
Object.assign(gameState, { list: newList });
}
4.4 錯誤 4:循環依賴
// ❌ 錯誤:Store 之間相互依賴
// authStore.ts
import { useUserInfoStore } from './userInfoStore';
export const useAuthStore = defineStore('authStore', () => {
const userInfoStore = useUserInfoStore(); // 依賴 userInfoStore
});
// userInfoStore.ts
import { useAuthStore } from './authStore';
export const useUserInfoStore = defineStore('useInfoStore', () => {
const authStore = useAuthStore(); // 依賴 authStore ❌ 循環依賴
});
// ✅ 正確:在 Composable 中組合
export function useInit() {
const authStore = useAuthStore();
const userInfoStore = useUserInfoStore();
async function initialize() {
await authStore.checkAuth();
if (authStore.isLogin) {
await userInfoStore.getUserInfo();
}
}
return { initialize };
}
4.5 錯誤 5:忘記 return
// ❌ 錯誤:忘記 return
export const useGameStore = defineStore('gameStore', () => {
const gameState = reactive({ list: [] });
function updateList(list) {
gameState.list = list;
}
// ❌ 忘記 return,組件無法訪問
});
// ✅ 正確
export const useGameStore = defineStore('gameStore', () => {
const gameState = reactive({ list: [] });
function updateList(list) {
gameState.list = list;
}
return { gameState, updateList }; // ✅ 必須 return
});
5. 面試重點整理
5.1 Store 設計原則
可以這樣回答:
在設計 Pinia Store 時,遵循幾個原則:1) 單一職責原則,每個 Store 只負責一個領域;2) 保持 Store 精簡,不要包含複雜的業務邏輯;3) 避免在 Store 中直接調用 API,應該在 Composable 中調用 API,Store 只負責存儲;4) 使用 TypeScript 完整型別定義,提升開發體驗。
關鍵點:
- ✅ 單一職責原則
- ✅ Store 精簡
- ✅ 職責分離
- ✅ TypeScript 使用