Store

Vuex

For vuex we are using, at least, two plugins.

  • vuex-module-configuration-composer to automagicly import our modules
  • vuex-persistedstate to persist in local storage certain modules (or none of them)

index.js default file (ready to go in most cases)

import Vue from 'vue'
import Vuex from 'vuex'
import { generateVuexStoreModuleConfiguration } from 'vuex-module-configuration-composer'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

const context = require.context('./modules', true, /index\.js$/)

const storeConfiguration = Object.assign(
  {
    plugins: [
      createPersistedState({
        paths: ['auth'],
      }),
    ],
  },
  generateVuexStoreModuleConfiguration(context)
)

export default new Vuex.Store(storeConfiguration)

File structure

src
└── store
    ├── index.js
    └── modules
        └── ...

We are not using root state, getters, actions and mutations. We will use a global module for global stuff that does not fit with any other module.

Rules

State

Avoid setting computed state

This might be obvious but try not to create repetitive data that could be easily computed with a getter.

// bad
export default {
    users: [],

    adminUsers: [],

    employeeUsers: []
}

Getters

Never create a computed in your component that only implies store data

If every element that computed needs already lives in the store you should do a getter.

// bad
computed: {
    isAdmin() {
        return this.$store.auth.state.user.isSuperAdmin || this.$store.auth.state.user.isSuperAdmin
    }
}

// good (in getters)

isAdmin: state => state.user.isSuperAdmin || state.user.isAdmin

Actions

Always destructure store context object

This practice would help to linter unused vars and see at a first sight which store functions are we using inside the action

// bad

myAction(store, payload) {
    store.commit(MY_MUTATION, payload)
}

// good

myAction({ commit }, payload) {
    commit(MY_MUTATION, payload)
}

Always import mutation constant

Avoid hardcoding mutation strings.

// bad

myAction({ commit }, payload) {
    commit('My Mutation', payload)
}

// good
import { MY_MUTATION } from './mutation-types'

myAction({ commit }, payload) {
    commit(MY_MUTATION, payload)
}

Mutations

Mutations types exported as const

Mutation types should be exported as const in order to get IDE autocompletion

export const MY_MUTATION = 'My Mutation'

Constants must be uppercased and value human readable

In order to quickly identify a mutation, the constant should be uppercased. In the other hand, its value should be human readable for debugging (You can use emojis if you want)

export const SING_IN = '🔒 Sign In'

Mutation names

We would try to use a convention naming for typical CRUD mutations

  • SET_ENTITY: Setting or Updating a pice of state
  • RESET_ENTITY: Setting a pice of state to its initial value
  • ADD_ENTITY: Adding an item to a collection
  • UPDATE_ENTITY: Updating an item in a collection
  • DELETE_ENTITY: Deleting an item from a collection

Mutating Arrays

In most cases we will use a single strategy mutating state in arrays.

[ADD_POST]: (state, post) => {
  state.posts = [...state.posts, post]
}

[UPDATE_POST]: (state, post) => {
  const index = state.posts.findIndex(p => p.id === post.id)
  state.posts.splice (index, 1, item)
}

[DELETE_POST]: (state, post) => {
  state.posts = state.posts.filter(p => p.id !== post.id)
}