Blog

Vuex in Nuxt: Going from Classic store mode to Modules

In working with the Vuex Store in Nuxt, there are 2 store modes that can be chosen:

  • Classic (deprecated): The presence of one single file store/index.js causes Nuxt to import Vuex and create store.
  • Modules: Every single .js inside the store directory becomes a namespaced module where each can have its own state, mutations, actions, getters, etc.

When starting out and learning, it can be easier to choose the Classic route and start off with a single store/index.js file. One such file that I've been working on in a project can be seen here as a Github gist.

Not only is this file becoming quite long, there are 3 different categories of state that I am using: Items, Loading, and User. I've grouped the relevant code under each to better illustrate. For example, all functions that involve mutations of Items are grouped under the // Items comment within mutations.

The first step to Modules nirvana is to create 3 files: store/items.js (gist), store/loading.js (gist), store/user.js (gist), and then move all the code from inside store/index.js to their relevant destinations. In my case, the store/index.js can be deleted.

Updating Vuex Store Methods

Now that the code is now in Modules, all methods that may have been used in components to interact with mutations, actions, and state in the old store/index.js will have to be updated. For example, the getItems action could be dispatched in Classic mode by using:

dispatch("getItems")

When moving an action into its own separate module file, leaving dispatch methods untouched could cause errors such as this:

Vuex error - unknown action type: GET_ITEMS

Since getItems is not in store/index.js anymore, the dispatch method will need to be updated to its new modular location:

dispatch("items/getItems")

The items/ portion refers to the store/items.js file. The getItems portion refers to the name of the action in that file.

Vuex Map Helpers

Vuex offers map helpers such as mapState, mapGetters, mapActions, and mapMutations. Utilize these to make the code less verbose which is helpful when using store methods multiple times in a component. For example, instead of using:

this.$store.dispatch("deleteItem", payload)

in a component's method, use mapActions by doing the following:

  1. Import the helper(s) needed from Vuex in your component:
    import { mapActions } from "vuex"
  2. Inside of the methods object of your component, add the mapper:
    ...mapActions({ removeItem: "items/deleteItem" }),
  3. Then, the new dispatch action can be rewritten as: this.removeItem(payload)

Dispatching Modular Actions within Actions

In store/items.js, I'm using dispatch methods to trigger actions of triggerBusyState and stopBusyState to start and stop a fancy animating loader. Since these 2 actions are now modularized in store/loading.js, the old way of dispatching them such as dispatch("triggerBusyState") will no longer work. Dispatching actions inside of other actions needs to be done like this:

dispatch("loading/triggerBusyState", null, { root: true })

The 2nd argument (in this case, null) needs to be there and the { root: true } object will instruct Vuex to look for triggerBusyState starting from the root store instead of from its current location of invocation store/items.

Some Notes

Having just store/index.js is actually Modules store mode where this file represents the root module. This article could be better described on how to move everything out of an overcrowded root module file into separate and more tidy module files.

It is still ok to have a root module store/index.js if needed. For example, the nuxtServerInit action only works in the root module.

My final working module mode store files (gists): items.js, loading.js, and user.js.