# Actions Actions are functions that dispatch mutations. Actions can be asynchronous and a single action can dispatch multiple mutations. An action expresses the intention for something to happen, and abstracts the details away from the component calling it. When a component wants to do something, it just calls an action - there's no need to worry about a callback or a return value, because actions result in state changes, and state changes will trigger the component's DOM to update - the component is completely decoupled from how that action is actually performed. Therefore, we usually perform API calls to data endpoints inside actions, and hide the asynchronous details from both the Components calling the actions, and the mutations triggered by the actions. > Vuex actions are in fact "action creators" in vanilla flux definitions, but I find that term more confusing than useful. ### Simple Actions It is common that an action simply triggers a single mutation. Vuex provides a shorthand for defining such actions: ``` js const vuex = new Vuex({ state: { count: 1 }, mutations: { INCREMENT (state, x) { state += x } }, actions: { // shorthand // just provide the mutation name. increment: 'INCREMENT' } }) ``` Now when we call the action: ``` js vuex.actions.increment(1) ``` It simply calls the following for us: ``` js vuex.dispatch('INCREMENT', 1) ``` Note any arguments passed to the action is also passed along to the mutation handler. ### Thunk Actions How about actions that involve logic depending on current state, or that need async operations? We can define these actions as **thunks** - essentially functions that return another function: ``` js const vuex = new Vuex({ state: { count: 1 }, mutations: { INCREMENT (state, x) { state += x } }, actions: { incrementIfOdd: function (x) { return function (dispatch, state) { if ((state.count + 1) % 2 === 0) { dispatch('INCREMENT', x) } } } } }) ``` Here, the outer function receives the arguments passed when calling the action. Then, it returns a function that gets 2 arguments: first is the `dispatch` function, and the second being the `state`. We are using ES5 syntax here to make things easier to understand. With ES2015 arrow functions we can "prettify" the above to the following: ``` js // ... actions: { incrementIfOdd: x => (dispatch, state) => { if ((state.count + 1) % 2 === 0) { dispatch('INCREMENT', x) } } } ``` The string shorthand is essentially syntax sugar for the following: ``` js actions: { increment: 'INCREMENT' } // ... equivalent to: actions: { increment: (...args) => dispatch => dispatch('INCREMENT', ...args) } ``` Why don't we just define the actions as simple functions that directly access `vuex.state` and `vuex.dispatch`? The reason is that such usage couples the action functions to the specific vuex instance. By using the thunk syntax, our actions only depend on function arguments and nothing else - this important characteristic makes them easy to test and hot-reloadable! ### Async Actions We can use the same thunk syntax for defining async actions: ``` js // ... actions: { incrementAsync: x => dispatch => { setTimeout(() => { dispatch('INCREMENT', x) }, 1000) } } ``` A more practical example is when checking out a shopping cart - we may need to trigger multiple mutations: one that signifies the checkout has started, one for success, and one for failure: ``` js // ... actions: { checkout: products => (dispatch, state) => { // save the current in cart items const savedCartItems = [...state.cart.added] // send out checkout request, and optimistically // clear the cart dispatch(types.CHECKOUT_REQUEST) // the shop API accepts a success callback and a failure callback shop.buyProducts( products, // handle success () => dispatch(types.CHECKOUT_SUCCESS), // handle failure () => dispatch(types.CHECKOUT_FAILURE, savedCartItems) ) } } ``` Again, all the component needs to do to perform the entire checkout is just calling `vuex.actions.checkout(products)`.