author: Fabio R de Carvalho
VUE
docs:
"Actions are similar to mutations, the differences being that:
So in many examples, we see an API call in action, which results in a commit of a mutation."
font: https://vuex.vuejs.org/guide/actions.html#actions
Mutations are synchronous, whereas actions can be asynchronous.
"This may look silly at first sight: if we want to increment the count, why don't we just call store.commit('increment') directly? Remember that mutations have to be synchronous. Actions don't. We can perform asynchronous operations inside an action" front: https://vuex.vuejs.org/guide/actions.html#dispatching-actions
To put it in another way: you don't need actions if your operations are synchronous, otherwise implement them. So, in the majority cases we only use Actions to develop requests or when we have to change two states in the same operation (business logic)
- Requests & async operations.
- Business logic: when we need to change more than two states in the same operation.
font: https://blog.logrocket.com/vuex-showdown-mutations-vs-actions/
"Sometimes we may need to compute derived state based on store state".
The getters will just look to some computation in the state and return it. So, do not do it inside the component itself.
"Example filtering through a list of items and counting them:"
doneTodos (state) {
return state.todos.filter(todo => todo.done)
}
With Decorators: Method-Style Access use vanilla vuex and return a function:
...
companies = []
get company() {
return (companyName: string) => { this.companies.find(company => company.name === companyName) };
}
font: https://vuex.vuejs.org/guide/actions.html
// eg. /app/store/posts.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators'
import { get } from 'axios'
interface PostEntity {
comments: string[]
}
@Module
export default class Posts extends VuexModule {
posts: PostEntity[] = [] // initialize empty for now
get totalComments(): number {
return this.posts
.filter(post => {
// Take those posts that have comments
return post.comments && post.comments.length
})
.reduce((sum, post) => {
// Sum all the lengths of comments arrays
return sum + post.comments.length
}, 0)
}
@Mutation
updatePosts(posts: PostEntity[]) {
this.posts = posts
}
@Action({ commit: 'updatePosts' })
async fetchPosts() {
return get('https://jsonplaceholder.typicode.com/posts')
}
}
font: https://github.com/championswimmer/vuex-module-decorators/blob/master/docs/pages/core/actions.md
...
actions: {
loadBooks({ commit }) {
commit('startLoading');
get('/api/books').then((response) => {
commit('setBooks', response.data.books);
commit('stopLoading');
});
},
},
...
font: https://github.com/championswimmer/vuex-module-decorators/blob/master/docs/pages/overview.md
...
books: Books;
isBooksLoading: boolean;
@Mutation
setIsBooksLoading(loading: boolean) {
this.isBooksLoading = loading;
}
@Mutation
setBooks(books: Books) {
this.books = books;
}
@Action
async updateBooks(): Promise<boolean> {
try{
this.context.commit("setIsBooksLoading", true);
const books = await get('/api/books');
this.context.commit("setBooks", books);
}catch(e){
return false;
}finally{
this.context.commit("setIsBooksLoading", false);
}
return true;
}
...
- ooade/vuex-examples: https://github.com/ooade/vuex-examples
- vueschool/learn-vuex: https://github.com/vueschool/learn-vuex/blob/master/src/store/modules/products.js & https://github.com/vueschool/learn-vuex/blob/master/src/store/modules/cart.js
- alpersonalwebsite/basic-vue-vuex: https://github.com/alpersonalwebsite/basic-vue-vuex/blob/master/src/store/modules/users.js
- TIGERB/easy-vue: https://github.com/TIGERB/easy-vue/blob/master/src/store/index.js
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.