5.1 Actions 核心概念
- Action
- store 中修改状态、执行业务逻辑的方法,等价于组件的
methods,可同步可异步。 - this 上下文
- 选项式 action 用普通函数定义,
this指向整个 store,可读写 state、调用其它 action。 - 异步 action
- 用
async/await处理请求,返回Promise,组件可 await 其结果。 - 跨 store 组合
- 一个 action 内导入并调用另一个 store,实现 store 之间协作。
- 错误处理
- action 内用 try/catch 捕获异常,或让 Promise reject 由调用方处理。
- 无 mutations
- Pinia 中 action 可直接改 state,不像 Vuex 需要在 action 里 commit mutation。
5.2 同步 Action
export const useCounterStore = defineStore("counter", {
state: () => ({ count: 0 }),
actions: {
increment() {
this.count++; // this 指向 store
},
incrementBy(step: number) {
this.count += step;
},
reset() {
this.count = 0;
},
},
});
action 别用箭头函数
选项式 action 必须用普通函数(increment() {}),箭头函数会让 this 指向错误的上下文,拿不到 store。
5.3 异步 Action
export const useUserStore = defineStore("user", {
state: () => ({ profile: null as Profile | null, loading: false }),
actions: {
async fetchProfile(id: number) {
this.loading = true;
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error("请求失败");
this.profile = await res.json();
return this.profile; // 可返回给调用方
} finally {
this.loading = false;
}
},
},
});
// 组件中调用并等待
const user = useUserStore();
await user.fetchProfile(1);
console.log(user.profile);
5.4 调用其它 Action
actions: {
async login(email: string, pwd: string) {
const { token, id } = await api.login(email, pwd);
this.token = token;
await this.fetchProfile(id); // 调用本 store 的另一个 action
},
},
5.5 跨 Store 组合
一个 store 的 action 里可以使用另一个 store——直接在函数内调用它的 use 函数:
import { defineStore } from "pinia";
import { useAuthStore } from "./auth";
export const useCartStore = defineStore("cart", {
state: () => ({ items: [] as Item[] }),
actions: {
async checkout() {
const auth = useAuthStore(); // 在 action 内取,保证已激活
if (!auth.isLoggedIn) throw new Error("请先登录");
await api.createOrder(auth.userId, this.items);
this.items = [];
},
},
});
为何在函数内部取 store
把 useAuthStore() 写在 action 内部(而非模块顶层),能保证 Pinia 已激活、且 SSR 每个请求拿到正确实例。顶层调用会在 Pinia 挂载前执行而报错。
5.6 错误处理策略
store 内吞掉错误
action 里 try/catch,把错误写进 state.error,组件读 state 显示提示。适合统一错误 UI。
向上抛给组件
action 不 catch,让 Promise reject,组件 try { await ... } 自行处理。适合针对性交互。
// 组件中捕获抛出的错误
try {
await cart.checkout();
toast.success("下单成功");
} catch (e) {
toast.error((e as Error).message);
}
5.7 组合式写法的 Action
export const useUserStore = defineStore("user", () => {
const profile = ref<Profile | null>(null);
const loading = ref(false);
// 普通函数即 action,直接操作 ref
async function fetchProfile(id: number) {
loading.value = true;
try {
profile.value = await (await fetch(`/api/users/${id}`)).json();
} finally {
loading.value = false;
}
}
return { profile, loading, fetchProfile };
});
5.8 小结与下一步
- Action = store 的方法层,可同步可异步,直接改 state(无 mutation)。
- 选项式 action 用普通函数,
this指向 store;组合式用普通函数直接改 ref。 - 跨 store 在 action 内部调用其它
useXxxStore(),保证时机正确。 - 下一章讲 在组件中使用 Store——useStore、storeToRefs 与 setup 外用法。