Actions
Actions相当于组件中的 methods 。可以使用defineStore()中的actions属性来定义它们,并且它们非常适合定义业务逻辑:
export const useStore = defineStore('main', {state: () => ({counter: 0,}),actions: {increment() {this.counter++},randomizeCounter() {this.counter = Math.round(100 * Math.random())},},})
和getters一样,actions通过this来访问整个store实例,还有完整的类型支持(和自动补全功能)。与它们不同的是,actions可以是异步的,您可以在它们内部进行任何API的调用,甚至其他操作!下面是一个使用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 = await api.post({ login, password })showTooltip(`Welcome back ${this.userData.name}!`)} catch (error) {showTooltip(error)// let the form component display the errorreturn error}},},})
您也可以完全自由地设置任何您想要的参数并返回任何东西。当调用actions时,一切都会被自动推断出来!
actions与methods调用类似:
export default defineComponent({setup() {const main = useMainStore()// call the action as a method of the storemain.randomizeCounter()return {}},})
访问其他 stores 的 actions
要使用另一个store,您可以直接在action内部使用它:
import { useAuthStore } from './auth-store'export const useSettingsStore = defineStore('settings', {state: () => ({// ...}),actions: {async fetchUserPreferences(preferences) {const auth = useAuthStore()if (auth.isAuthenticated) {this.preferences = await fetchPreferences()} else {throw new Error('User must be authenticated')}},},})
setup() 中的用法
您可以直接调用任何action作为store的方法:
export default {setup() {const store = useStore()store.randomizeCounter()},}
Options API 中的用法
对于以下示例,您可以假设创建了以下store:
// Example File Path:// ./src/stores/counterStore.jsimport { defineStore } from 'pinia'const useCounterStore = defineStore('counterStore', {state: () => ({counter: 0}),actions: {increment() {this.counter++}}})
使用 setup()
虽然Composition API并不适合所有人,但setup()钩子可以让Pinia更容易在Options API中使用。不需要额外的辅助函数!
import { useCounterStore } from '../stores/counterStore'export default {setup() {const counterStore = useCounterStore()return { counterStore }},methods: {incrementAndPrint() {counterStore.increment()console.log('New Count:', counterStore.count)},},}
不使用 setup()
如果您根本不想使用Composition API,您可以使用mapActions()辅助函数将actions属性映射为组件中的methods:
import { mapActions } from 'pinia'import { useCounterStore } from '../stores/counterStore'export default {methods: {// gives access to this.increment() inside the component// same as calling from store.increment()...mapActions(useCounterStore, ['increment']),// same as above but registers it as this.myOwnName()...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),},}
订阅 actions
可以使用store.$onAction()来观察actions及其结果。传递给它的回调函数在action本身之前执行。在处理promises之后,允许您在action resolves之后执行函数。类似地,onError允许你在action抛出或rejects时执行函数。这些对于在运行时跟踪错误很有用,类似于Vue文档中的这个技巧。
下面是一个在运行actions之前和resolve/reject之后记录日志的示例。
const unsubscribe = someStore.$onAction(({name, // name of the actionstore, // store instance, same as `someStore`args, // array of parameters passed to the actionafter, // hook after the action returns or resolvesonError, // hook if the action throws or rejects}) => {// a shared variable for this specific action callconst startTime = Date.now()// this will trigger before an action on `store` is executedconsole.log(`Start "${name}" with params [${args.join(', ')}].`)// this will trigger if the action succeeds and after it has fully run.// it waits for any returned promisedafter((result) => {console.log(`Finished "${name}" after ${Date.now() - startTime}ms.\nResult: ${result}.`)})// this will trigger if the action throws or returns a promise that rejectsonError((error) => {console.warn(`Failed "${name}" after ${Date.now() - startTime}ms.\nError: ${error}.`)})})// manually remove the listenerunsubscribe()
默认情况下,action订阅被绑定到添加它们的组件(如果store在组件的setup()中)。这就意味着,当组件被卸载时,它们将被自动删除。如果你想在组件卸载后保留它们,传true作为第二个参数,以将操作订阅与当前组件分离:
export default {setup() {const someStore = useSomeStore()// this subscription will be kept after the component is unmountedsomeStore.$onAction(callback, true)// ...},}
