actions
Action 相当于组件中的method
。它们可以通过defineStore()
中的actions属性来定义,并且它们也是定义业务逻辑的完美选择。
export const useStore = defineStore('main', { state: () => ({ count: 0, }), actions: { // since we rely on `this`, we cannot use an arrow functionincrement() { this.count++ },randomizeCounter() { this.count = Math.round(100 * Math.random()) }, }, })
类似 getter,action 也可通过this
访问整个 store 实例,并支持完整的类型标注(以及自动补全)。不同的是,action 可以是异步的,你可以在它们里面使用await
调用任何 API,以及其他 action!下面是一个使用 Mande 的例子。请注意,你使用什么库并不重要,只要你得到的是一个Promise,你甚至可以(在浏览器中)使用原生fetch
函数:
import { mande } from 'mande' const api = mande('/api/users') export const useUsers = defineStore('users', { state: () => ({ userData: null, // ... }), actions: { async registerUser(login, password) { try { this.userData = awaitapi.post ({ login, password }) showTooltip(`Welcome back ${this.userData.name}!`) } catch (error) { showTooltip(error) // 让表单组件显示错误 return error } }, }, })
想要使用另一个 store 的话,那你直接在 action 中调用:
import { useAuthStore } from './auth-store' export const useSettingsStore = defineStore('settings', { state: () => ({ preferences: null, // ... }), actions: { async fetchUserPreferences() { const auth = useAuthStore() if (auth.isAuthenticated ) { this.preferences = await fetchPreferences() } else { throw new Error('User must be authenticated') } }, }, })
Composition API 组件中,调用 action
当组件是 Composition API 编程方式时,在setup()
中,将任何 action 作为 store 的一个方法直接调用:
<script> export default { setup() { const store = useCounterStore() store.randomizeCounter() }, } </script>
<script setup> const store = useCounterStore() store.randomizeCounter() </script>
你也完全可以自由地设置,任何你想要的参数以及返回任何结果。当调用 action 时,一切类型也都是可以被自动推断出来的。
在组件使用中,调用store 中 useCounterStore 的 actions <script> export default defineComponent({ setup() { const store = useCounterStore() // call the action as a method of the store store.randomizeCounter() return {} }, }) </script>
Options API 组件中,调用 action
在下面的例子中,你可以假设相关的 store 已经创建了
// Example File Path: // ./src/stores/counter.js <script> import { defineStore } from 'pinia', export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } }) </script>
当组件是 Options API 编程方式时,在setup()
钩子中,直接调用使用 Pinia,然后在methods
中,直接调用 action。
<script> import { useCounterStore } from '../stores/counter' export default { setup() { const counterStore = useCounterStore() return { counterStore } }, methods: { incrementAndPrint() { this.counterStore.increment() console.log('New Count:', this.counterStore.count) }, }, } </script>
当组件是 Options API 编程方式时,没有使用setup()
钩子调用 Pinia,那么在methods
中,调用 action,可以使用mapActions()
辅助函数,将 action 属性映射为组件中的方法:
<script> import { mapActions } from 'pinia' import { useCounterStore } from '../stores/counter' export default { methods: { // 访问组件内的 this.increment() // 与从 store.increment() 调用相同 ...mapActions(useCounterStore, ['increment']) // 与上述相同,但将其注册为this.myOwnName() ...mapActions(useCounterStore, { myOwnName: 'increment' }), }, } </script>
订阅 action
可以使用store.$onAction()
来监听 action 和它们的结果。传递给它的回调函数会在 action 本身之前执行。after
表示在 promise 解决之后,允许你在 action 解决后执行一个一个回调函数。同样地,onError
允许你在 action 抛出错误或 reject 时执行一个回调函数。这些函数对于追踪运行时错误非常有用,类似于Vue docs 中的这个提示。
这里有一个例子,在运行 action 之前以及 action resolve/reject 之后打印日志记录。
const unsubscribe = someStore.$onAction( ({ name, // action 名称 store, // store 实例,类似 `someStore` args, // 传递给 action 的参数数组 after, // 在 action 返回或解决后的钩子 onError, // action 抛出或拒绝的钩子 }) => { // 为这个特定的 action 调用提供一个共享变量 const startTime = Date.now() // 这将在执行 "store "的 action 之前触发。 console.log(`Start "${name}" with params [${args.join(', ')}].`) // 这将在 action 成功并完全运行后触发. // 它等待着任何返回的 promise after((result) => { console.log( `Finished "${name}" after ${ Date.now() - startTime }ms.\nResult: ${result}.` ) }) // 如果 action 抛出或返回一个拒绝的 promise,这将触发 onError((error) => { console.warn( `Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.` ) }) } ) // 手动删除监听器 unsubscribe()
默认情况下,action 订阅器会被绑定到添加它们的组件上(如果 store 位于组件的setup()
中)。这意味着,当该组件被卸载时,它们将被自动删除。如果你想在组件卸载后依旧保留它们,请将true
作为第二个参数传递给 action 订阅器,以便将其从当前组件中分离:
export default { setup() { const someStore = useSomeStore() // 在组件被卸载后,这个订阅依旧会被保留 someStore.$onAction (callback, true) // ... }, }