Pinia 使用实践
在多品牌平台项目中,Pinia Store 在组件和 Composables 中的使用方式,以及 Store 之间的通讯模式。
1. 面试回答主轴
- 组件使用:使用
storeToRefs保持响应性,Actions 可以直接解构。 - Composables 组合:在 Composables 中组合多个 Store,封装业务逻辑。
- Store 通讯:推荐在 Composable 中组合,避免循环依赖。
2. 在组件中使用 Store
2.1 基本使用
<script setup lang="ts">
import { useAuthStore } from 'stores/authStore';
// 直接使用 store 实例
const authStore = useAuthStore();
// 访问 state
console.log(authStore.access_token);
// 调用 action
authStore.setToptVerified(true);
// 访问 getter
console.log(authStore.isLogin);
</script>
2.2 使用 storeToRefs 解构(重要!)
<script setup lang="ts">
import { useAuthStore } from 'stores/authStore';
import { storeToRefs } from 'pinia';
const authStore = useAuthStore();
// ❌ 错误:会失去响应性
const { access_token, isLogin } = authStore;
// ✅ 正确:保持响应性
const { access_token, isLogin } = storeToRefs(authStore);
// ✅ Actions 可以直接解构(不需要 storeToRefs)
const { setToptVerified } = authStore;
</script>
为什么直接解构会失去响应性?
- Pinia 的 state 和 getters 是响应式的
- 直接解构会破坏响应式连接
storeToRefs会将每个属性转换为ref,保持响应性- Actions 本身不是响应式的,所以可以直接解构
3. 在 Composables 中使用 Store
3.1 实际案例:useGame.ts
Composables 是组合 Store 逻辑的最佳场所。
import { useGameStore } from 'stores/gameStore';
import { useProductStore } from 'stores/productStore';
import { storeToRefs } from 'pinia';
export function useGame() {
// 1️⃣ 引入多个 stores
const gameStore = useGameStore();
const productStore = useProductStore();
// 2️⃣ 解构 state 和 getters(使用 storeToRefs)
const { gameState } = storeToRefs(gameStore);
const { productState } = storeToRefs(productStore);
// 3️⃣ 解构 actions(直接解构)
const { initAllGameList, updateAllGameList } = gameStore;
// 4️⃣ 组合逻辑
async function initGameTypeList() {
const { status, data } = await useApi(getGameTypes);
if (status) {
setGameTypeList(data.list);
setGameTypeMap(data.map);
}
}
// 5️⃣ 返回给组件使用
return {
gameState,
productState,
initGameTypeList,
initAllGameList,
};
}
面试重点:
- Composables 是组合 Store 逻辑的最佳场所
- 使用
storeToRefs确保响应性 - Actions 可以直接解构
- 将复杂的业务逻辑封装在 composable 中
4. Store 之间的通讯
4.1 方法一:在 Store 内部调用其他 Store
import { defineStore } from 'pinia';
import { useUserInfoStore } from './userInfoStore';
export const useAuthStore = defineStore('authStore', {
actions: {
async login(credentials) {
const { status, data } = await api.login(credentials);
if (status) {
this.access_token = data.access_token;
// 调用其他 store 的方法
const userInfoStore = useUserInfoStore();
userInfoStore.setStoreUserInfo(data.user);
}
},
},
});
4.2 方法二:在 Composable 中组合多个 Store(推荐)
export function useInit() {
const authStore = useAuthStore();
const userInfoStore = useUserInfoStore();
const gameStore = useGameStore();
async function initialize() {
// 依序执行多个 store 的初始化
await authStore.checkAuth();
if (authStore.isLogin) {
await userInfoStore.getUserInfo();
await gameStore.initGameList();
}
}
return { initialize };
}
面试重点:
- ✅ 推荐在 Composable 中组合多个 Store
- ❌ 避免 Store 之间的循环依赖
- 保持 Store 的单一职责原则
5. 实战案例:用户登入流程
这是一个完整的 Store 使用流程,涵盖了多个 Store 的协作。