Skip to content

Instantly share code, notes, and snippets.

@stembrino
Last active July 6, 2023 14:52
Show Gist options
  • Save stembrino/773a9e964a528b4d8799f541a451654b to your computer and use it in GitHub Desktop.
Save stembrino/773a9e964a528b4d8799f541a451654b to your computer and use it in GitHub Desktop.

author: Fabio R de Carvalho

Vuex & vuex-module-decorators

vuex-store

The problem

How to proper use the stores in Vuex/vuex-module-decorator 🤯

Rules 👩‍⚖️

Actions X Mutations

VUE docs:

"Actions are similar to mutations, the differences being that:

- Instead of mutating the state, actions commit mutations.

- Actions can contain arbitrary asynchronous operations.

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

When use Mutation and when use Action❓

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)

Actions

  1. Requests & async operations.
  2. 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/

Getters

Vue & Vuex

"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

vuex-module-decorators

Example:

// 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

Loading State Example (LogRocket site)

...
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

Refactor with decorators 🛠️

...
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;
}
...

GitHub Examples Repository

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment