Categories
JavaScript JavaScript Basics

Introduction to JavaScript Modules

JavaScript modules allow us to divide code into small pieces. They also let us keep some code private while exposing other pieces of code that can be imported into another module.

In this article, we’ll look at how to use define and use them.

Named Exports

Names exports start with the export keyword and they expose items from a module to the outside. Then we can import them somewhere else.

There can be multiple named exports in one module. For instance, we can write:

export const foo = 1;  
export let bar = 1;

Then we can import them into another module as follows:

import { foo, bar } from "./module";
const baz = foo + bar;

We can also import the whole module with the * sign as follows:

import * as module from "./module";
const baz = module.foo + module.bar;

Default Export

We can export one default export using the export default keywords. For instance, we can write:

export default 1;

Then import it as follows:

import foo from "./bar";  
const baz = foo;

We can also export functions and class as follows:

export default () => {};

or:

export default class {}

We don’t need a semicolon at the end of the class export.

Also, we can define default exports with the following code:

const foo = 1;  
export { foo as default };

Browser Differences Between Scripts and Modules

In browsers, scripts are denoted by the script tag. Modules are the same, but it’s denoted by the type attribute with value module .

Scripts are not in strict mode by default, while modules are in strict mode by default.

Top-level variables are global in scrips and are local to the module in modules.

Top-level value of this is window in scripts and it’s undefined in modules.

Scripts are run synchronously while modules are run asynchronously.

There are no import statements in scripts and we can selectively import module members in modules.

We can programmatically import both scripts and modules using promise-based APIs.

Module Characteristics

ES6 modules can be statically analyzed for static checking, optimization, and more. It has a declarative syntax for importing and exporting.

Imports are hoisted to the top so that they can be referenced anywhere in the module.

For instance, if we have:

export const foo = 1;

Then we can import it as follows:

const baz = foo;
import { foo } from "./bar";

Also, they must be at the top-level. Therefore, we can’t have something like:

{  
  import { foo } from "./bar";  
  const baz = foo;  
}

Imports are Read-Only Views on Exports

ES6 imports are read-only views on export entities. Connections to variables inside the module that imported the export remain live.

For instance, if we have:

export const foo = 1;

Then if we have the following:

import { foo } from "./bar";  
foo = 1;

Then we’ll get a ‘”foo” is read-only.’ error since it’s referencing the export directly in a read-only manner.

We get the same result if we change the const to let .

Cyclic Dependencies

If module A and B import members from each other, then we call it a cyclic dependency. This is supported with ES6 modules. For instance, if we have:

index.js :

import { foo } from "./bar";
export const baz = 2;

bar.js :

import { baz } from "./index";
export let foo = 1;

Then the modules are cyclic dependencies since we import a member from bar inindex and we import a member from index in bar .

This works because imports just refer to the original data, so it doesn’t matter when they come from.

Importing Styles

We can import JavaScript modules in various ways. One way is the default import, which is how we import members from a module.

For instance, we can write:

bar.js :

let foo = 1;  
export default foo;

Then we can import it as follows:

import foo from "./bar";

Named imports can be imported as follows. Given the following named exports:

export let foo = 1;

Then we can import it as follows:

import { foo } from "./bar";

We can rename named exports by using the as keyword as follows:

import { foo as baz } from "./bar";

We can also rename default exports as follows:

import { default as foo } from "./bar";

We can also have empty where we don’t import anything. Instead, we run what’s included in the module.

For instance, if we have the following in bar.js :

console.log("bar");

Then we can run the code in bar.js as follows:

import "./bar";

Therefore, we should see 'bar' logged in the console log.

Conclusion

ES6 modules are a great way to divide code into small chunks. We can export module members and import them in another file. Imported members are read-only. Modules are in strict mode by default, so we avoid lots of issues with non-strict mode.

Categories
JavaScript Vue

Adding Getters to a Vuex Store

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add getters to a Vuex store to add states derived from other store states.

Adding Getters to Our Store

We can add a getter to our Vuex store by adding a getters property as follows:

index.js :

const store = new Vuex.Store({  
  state: {  
    todos: [  
      { id: 1, text: "todo1", done: true },  
      { id: 2, text: "todo2", done: false }  
    ]  
  },  
  getters: {  
    doneTodos: state => {  
      return state.todos.filter(todo => todo.done);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: {  
    doneTodos() {  
      return this.$store.getters.doneTodos;  
    },  
    ...Vuex.mapState({  
      todos: "todos"  
    })  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <div>  
        <p>Todos:</p>  
        <div v-for="todo of todos">{{todo.text}}</div>  
        <p>Done Todos:</p>  
        <div v-for="todo of doneTodos">{{todo.text}}</div>  
      </div>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code, we have a getters object:

getters: {  
  doneTodos: state => {  
    return state.todos.filter(todo => todo.done);  
  }  
}

that derives the state from the todos state.

Then we accessed doneTodos getter by writing:

computed: {  
  doneTodos() {  
    return this.$store.getters.doneTodos;  
  },  
  ...Vuex.mapState({  
    todos: "todos"  
  })  
}

in the Vue instance.

Then the items are rendered in our template and we get:

Todos:todo1  
todo2  
Done Todos:todo1

displayed.

Method-Style Access

We can return a function in a getter function so that we can call the getters from a component with one or more arguments.

For instance, if we want to make a getter that gets a todo by ID, we can write the following:

index.js :

const store = new Vuex.Store({  
  state: {  
    todos: [  
      { id: 1, text: "todo1", done: true },  
      { id: 2, text: "todo2", done: false }  
    ]  
  },  
  getters: {  
    getTodoById: state => id => {  
      return state.todos.find(todo => todo.id === id);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapState({  
    todos: "todos"  
  }),  
  methods: {  
    getTodoById(id) {  
      return this.$store.getters.getTodoById(id);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      {{getTodoById(1).text}}  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then we see todo1 displayed on the screen.

We have the following code to define our getter:

getters: {  
  getTodoById: state => id => {  
    return state.todos.find(todo => todo.id === id);  
  }  
}

The code above returns a function and then returns a todo with the given ID.

Then we access it in our Vue instance by defining the getTodoById method as follows:

getTodoById(id) {  
  return this.$store.getters.getTodoById(id);  
}

Finally, we render it in our template by writing:

{{getTodoById(1).text}}

The mapGetters Helper

We can use the mapGetters helper to map our getters to computed properties as follows:

index.js :

const store = new Vuex.Store({  
  state: {  
    todos: [  
      { id: 1, text: "todo1", done: true },  
      { id: 2, text: "todo2", done: false }  
    ]  
  },  
  getters: {  
    doneTodosCount: state => {  
      return state.todos.filter(todo => todo.done).length;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapGetters(["doneTodosCount"])  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.j"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      {{doneTodosCount}}  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then we get 1 displayed since we mapped doneTodosCount getter to a computed property with the same name with:

computed: Vuex.mapGetters(["doneTodosCount"])

Conclusion

We can use getters to add states that are derived from another state.

To define a getter, we add a method to the getters property that returns something derived from the state or a function that derives something from a state.

To include it in our components, we can use the this.$store.getters method or use the mapGetters method.

Categories
JavaScript Vue

Adding Mutations to a Vuex Store

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add mutations to a Vuex store so that we can update the store’s state and propagate the change to components that uses the store.

Adding Mutations

We can add a mutation by putting in a function that changes the state by taking it from the parameter and then mutating it.

For example, we can write the following code:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

Then we can run the mutation function by running:

store.commit('increase')

Then state.count should go up by 1.

We can’t run mutation functions directly.

Commit with Payload

If we want to pass our own argument to it, we can add it after the state parameter, so we write:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, num) {  
      state.count += num;  
    }  
  }  
});

Then we can commit the mutation by writing:

store.commit('increase', 10)

Then state.count should go up by 10.

The second parameter is usually an object, so we can access property values by writing:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

Then we can commit the mutation by writing:

store.commit('increase', {  
  amount: 10  
})

Any state changes will be observed by components automatically if they access the store from within it.

Vue’s reactivity rules like initializing initial state and using Vue.set to update objects, etc. all applies to Vuex stores.

We can replace strings for mutation names with constants by assigning them to constants.

For example, we can change the example we have above to:

const INCREASE = "increase";

const store = new Vuex.Store({  
  state: {  
    count: 1  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

store.commit(INCREASE, { amount: 10 });

JavaScript since ES6 can have dynamic property names, so we can take advantage of that to replace names with constants.

Mutations Must Be Synchronous

Mutations must be synchronous because they’re untrackable since asynchronous code can be called at any time rather than line by line like synchronous code is.

Committing Mutations in Components

We can either use this.$store.commit to commit mutations or we can use Vuex’s helper methods to do so.

this.$store.commit

For example, we can use this.$store.commit as follows:

index.js :

const INCREASE = "increase";const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapState(["count"]),  
  methods: {  
    increase(amount) {  
      this.$store.commit(INCREASE, { amount });  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increase(10)">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we have the increase method as follows:

increase(amount) {  
  this.$store.commit(INCREASE, { amount });  
}

This is called by our template when we click the Increase button.

this.$store.commit(INCREASE, { amount }); will increase state.count by the amount we pass in, which is 10.

Then we get the state back by using mapState so we can display it in our template.

When we click Increase, we get 10, 20, 30, etc.

mapMutations

We can use mapMutations to map mutations to methods in our component as follows:

index.js :

const INCREASE = "increase";

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    [INCREASE](state, payload) {  
      state.count += payload.amount;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: Vuex.mapState(["count"]),  
  methods: {  
    ...Vuex.mapMutations([INCREASE])  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increase({amount: 10})">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, mapMutations maps the mutation methods to the component methods.

So:

...Vuex.mapMutations([INCREASE])

maps the increase method adds an increase method to the component which calls this.$store.commit(INCREASE) .

INCREASE is the string 'increase' that we have in the first line.

In the template, we just called increase({amount: 10}) when the Increase button is clicked to update state.count in the store.

Conclusion

We add mutations to our Vuex store to update the state of our store.

To do this, we add methods under the mutations object.

Then we can call this.$store.commit or use mapMutations to map mutation methods in the store to component methods.

Mutations must be synchronous since they need to be trackable.

Categories
JavaScript Vue

Adding Actions to a Vuex Store

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add actions to our Vuex store to change the store’s state.

What are Actions?

Actions are similar to mutations, but they commit mutations instead of mutating the state. Actions can also commit asynchronous operations unlike mutations.

For example, we can add a simple action as follows:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  },  
  actions: {  
    increase(context) {  
      context.commit("increase");  
    }  
  }  
});

An action takes a context object, which we can use to call commit to commit a mutation.

Dispatching Actions

We can dispatch actions by calling store.dispatch('increase') .

It’s much more useful than commit mutations directly because we can run asynchronous operations with it.

For example, we can dispatch an action as follows in Vue app:

index.js :

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increaseAsync({ commit }, payload) {  
      setTimeout(() => {  
        commit("increase", payload);  
      }, 1000);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  methods: {  
    ...Vuex.mapActions(["increaseAsync"])  
  },  
  computed: {  
    ...Vuex.mapState(["count"])  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src=[https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increaseAsync({amount: 10})">Increase</button>  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we have the action increaseAsync with the following code:

increaseAsync({ commit }, payload) {  
  setTimeout(() => {  
    commit("increase", payload);  
  }, 1000);  
}

In the action method, we commit the increase mutation with a payload object that we pass in when we dispatch the action.

In the Vue instance, we have:

methods: {  
    ...Vuex.mapActions(["increaseAsync"])  
},  
computed: {  
  ...Vuex.mapState(["count"])  
}

which maps the actions in the store by calling mapActions , and added computed properties by mapping them from the store by using mapState so we get a count property which is computed from state.count as a computed property.

Then in the template, we call increaseAsync when we press the Increase button to update state.count after 1 second.

Finally, we should see the number updated since we mapped the state from the store.

Composing Actions

We can chain actions that return promises.

For example, we can create an action to update 2 counts as follows:

index.js :

const store = new Vuex.Store({  
  state: {  
    count1: 0,  
    count2: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count1 += payload.amount;  
    },  
    decrease(state, payload) {  
      state.count2 -= payload.amount;  
    }  
  },  
  actions: {  
    async increaseAsync({ commit }, payload) {  
      return Promise.resolve(commit("increase", payload));  
    },  
    async decreaseAsync({ commit }, payload) {  
      return Promise.resolve(commit("decrease", payload));  
    },  
    async updateCounts({ dispatch }, payload) {  
      await dispatch("increaseAsync", payload);  
      await dispatch("decreaseAsync", payload);  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  methods: {  
    ...Vuex.mapActions(["updateCounts"])  
  },  
  computed: {  
    ...Vuex.mapState(["count1", "count2"])  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="updateCounts({amount: 10})">Update Counts</button>  
      <p>Count 1: {{count1}}</p>  
      <p>Count 2: {{count2}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we have the updateCounts action switch calls dispatch with the increaseAsync action and payload . Then it calls dispatch with the decreaseAsync action and payload .

increaseAsync commits the increase mutation, and decreaseAsync commis the decrease mutation.

Since they all have Promise.resolve , they’re all async.

Then we include the updateCounts action from the store in our Vue instance with mapActions . And we also include the count1 and count2 states with mapState .

Then when we click the Update Counts button, we call updateCounts , and then count1 and count2 are updated as we click the button. count1 should increase by 10 each time and count2 should decrease by 10 each time we click it.

Conclusion

We can use actions to commit one or more mutations or dispatch other actions.

It’s handy for grouping store operations together and running asynchronous code since mutations are always synchronous.

We can use mapActions to include them in our components.

Actions are dispatched by calling dispatch , while mutations are committed with the commit method.

Categories
JavaScript Vue

Adding Modules to a Vuex Store

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add modules to separate a Vuex store into smaller parts.

Dividing a Store into Modules

Vuex uses a single state tree. This means the states are located in one big object. This will be bloated is our app grows big.

To make a Vuex store easier to scale, it can be separated into modules. Each module can have its own state, mutations, getters, and actions.

The state parameter in mutations and getters are the module’s local state.

By default, all actions, mutations, and getters inside modules are registered under a global namespace. This allows multiple modules to react to the same mutation or action type.

We can divide our store into module as in the following example:

index.js :

const moduleA = {  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const moduleB = {  
  state: {  
    count: 1  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const store = new Vuex.Store({  
  modules: {  
    a: moduleA,  
    b: moduleB  
  }  
});

console.log(store.state.a.count);  
console.log(store.state.b.count);

Then in the console.log output, we should see 0 and 1 since moduleA ‘s initial count state is 0 and moduleB ‘s initial count state is 1.

To make each module self-contained, we have to namespace it by setting the namespaced option to true .

We can namespace a module and then call dispatch on actions after namespacing the modules as follows:

index.js :

const moduleA = {  
  namespaced: true,  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const moduleB = {  
  namespaced: true,  
  state: {  
    count: 1  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const store = new Vuex.Store({  
  modules: {  
    a: moduleA,  
    b: moduleB  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: {  
    ...Vuex.mapState({  
      a: state => state.a,  
      b: state => state.b  
    })  
  },  
  methods: {  
    increaseA(payload) {  
      this.$store.dispatch("a/increase", payload);  
    },  
    increaseB(payload) {  
      this.$store.dispatch("b/increase", payload);  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increaseA({amount: 10})">Increase</button>  
      <button @click="increaseB({amount: 10})">Increase</button>  
      <p>A Count: {{a.count}}</p>  
      <p>B Count: {{b.count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we have namespaced: true set in each module, and then we added 2 methods to our Vue instance to dispatch the namespaced actions:

increaseA(payload) {  
  this.$store.dispatch("a/increase", payload);  
}

and:

increaseB(payload) {  
  this.$store.dispatch("b/increase", payload);  
}

Since we have namespaced set to true , we have to dispatch the actions by passing in “a/increase” and “b/increase” to dispatch .

Then once we clicked the buttons, our methods are called to dispatch the actions and the numbers will increase.

Register Global Action in Namespaced Modules

We can also register global actions in namespaced modules, by setting the root option to true and place the action definition in the function handler.

To do register a global action, we can write something like the following code:

index.js :

const moduleA = {  
  namespaced: true,  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const moduleB = {  
  namespaced: true,  
  state: {  
    count: 1  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const rootModule = {  
  actions: {  
    increaseAll: {  
      root: true,  
      handler(namespacedContext, payload) {  
        namespacedContext.commit("a/increase", payload);  
        namespacedContext.commit("b/increase", payload);  
      }  
    }  
  }  
};

const store = new Vuex.Store({  
  modules: {  
    a: moduleA,  
    b: moduleB,  
    root: rootModule  
  }  
});

new Vue({  
  el: "#app",  
  store,  
  computed: {  
    ...Vuex.mapState({  
      a: state => state.a,  
      b: state => state.b  
    })  
  },  
  methods: {  
    ...Vuex.mapActions(["increaseAll"])  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increaseAll({amount: 10})">Increase All</button>  
      <p>A Count: {{a.count}}</p>  
      <p>B Count: {{b.count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

In the code above, we added the rootModule which has the global action as follows:

const rootModule = {  
  actions: {  
    increaseAll: {  
      root: true,  
      handler(namespacedContext, payload) {  
        namespacedContext.commit("a/increase", payload);  
        namespacedContext.commit("b/increase", payload);  
      }  
    }  
  }  
};

A global action has the root option set to true and a handler method which is used to dispatch actions from any module.

Then in the Vue instance, we have:

methods: {  
  ...Vuex.mapActions(["increaseAll"])  
}

to map the increaseAll action to a method in the Vue instance.

Then in the template, we have:

<button @click="increaseAll({amount: 10})">Increase All</button>

to call the increaseAll method returned from the mapActions method when the button is clicked.

Then we should both numbers increasing since we mapped both module’s state to the Vue instance’s data.

Dynamic Module Registration

We can also register a module dynamically by using the store.registerModule method as follows:

index.js :

const moduleA = {  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state, payload) {  
      state.count += payload.amount;  
    }  
  },  
  actions: {  
    increase({ commit }, payload) {  
      commit("increase", payload);  
    }  
  }  
};

const store = new Vuex.Store({});

store.registerModule("a", moduleA);

new Vue({  
  el: "#app",  
  store,  
  computed: {  
    ...Vuex.mapState({  
      a: state => state.a  
    })  
  },  
  methods: {  
    ...Vuex.mapActions(["increase"])  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <button @click="increase({amount: 10})">Increase</button>  
      <p>A Count: {{a.count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

The store.registerModule takes a string for the module name, and then an object for the module itself.

Then we can call the helpers to map getters to computed properties and actions/mutations to methods. In the code above, we have the increase action mapped to a method.

Then we can call it in our template as usual.

Conclusion

If our Vuex store is big, we can divide it into modules.

We can register modules when we create the store or dynamically with registerModule .

Then we can map actions/mutations by their name as usual, and we can map the state by accessing state.a.count , where a is the module name, and count is the state name. Replace it with our own module and state names if the code is different.

We can also namespace the modules. Then we dispatch the actions starting with the module name and a slash instead of just the name.