How to Use Vuex in Vue.js

How to Use Vuex in Vue.js

While using vuejs with vue what I find very important is dividing states into modules. eg: auth module, user module, status module, post module. each with their own state, actions, mutations, and getters.

Due to using a single state tree, all state of our application is contained inside one big object. However, as our application grows in scale, the store can get really bloated.

To help with that, Vuex allows us to divide our store into modules. Each module can contain its own state, mutations, actions, getters, and even nested modules - it's fractal all the way down:

const moduleA = {
 state: { ... },
 mutations: { ... },
 actions: { ... },
 getters: { ... }
}

const moduleB = {  state: { ... },  mutations: { ... },  actions: { ... } }

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

store.state.a // -> moduleA's state store.state.b // -> moduleB's state

Module Local State

Inside a module's mutations and getters, the first argument received will be the module's local state.

const moduleA = {
 state: { count: 0 },
 mutations: {
  increment (state) {
   // state is the local module state
   state.count++
  }
 },

 getters: {   doubleCount (state) {    return state.count * 2   }  } }

Similarly, inside module actions, context.state will expose the local state, and root state will be exposed as context.rootState:

const moduleA = {
 // ...
 actions: {
  incrementIfOddOnRootSum ({ state, commit, rootState }) {
   if ((state.count + rootState.count) % 2 === 1) {
    commit('increment')
   }
  }
 }
}

Also, inside module getters, the root state will be exposed as their 3rd argument:

const moduleA = {
 // ...
 getters: {
  sumWithRootCount (state, getters, rootState) {
   return state.count + rootState.count
  }
 }
}

Namespacing

By default, actions, mutations and getters inside modules are still registered under the global namespace - this allows multiple modules to react to the same mutation/action type.

If you want your modules to be more self-contained or reusable, you can mark it as namespaced with namespaced: true. When the module is registered, all of its getters, actions and mutations will be automatically namespaced based on the path the module is registered at. For example:

const store = new Vuex.Store({
 modules: {
  account: {
   namespaced: true,

   // module assets    state: { ... }, // module state is already nested and not affected by namespace option    getters: {     isAdmin () { ... } // -> getters['account/isAdmin']    },    actions: {     login () { ... } // -> dispatch('account/login')    },    mutations: {     login () { ... } // -> commit('account/login')    },

   // nested modules    modules: {     // inherits the namespace from parent module     myPage: {      state: { ... },      getters: {       profile () { ... } // -> getters['account/profile']      }     },

    // further nest the namespace     posts: {      namespaced: true,

     state: { ... },      getters: {       popular () { ... } // -> getters['account/posts/popular']      }     }    }   }  } })

Namespaced getters and actions will receive localized gettersdispatch and commit. In other words, you can use the module assets without writing prefix in the same module. Toggling between namespaced or not does not affect the code inside the module.

Accessing Global Assets in Namespaced Modules

If you want to use global state and getters, rootState and rootGetters are passed as the 3rd and 4th arguments to getter functions, and also exposed as properties on the context object passed to action functions.

To dispatch actions or commit mutations in the global namespace, pass { root: true } as the 3rd argument to dispatch and commit.

modules: {
 foo: {
  namespaced: true,

  getters: {    // getters is localized to this module's getters    // you can use rootGetters via 4th argument of getters    someGetter (state, getters, rootState, rootGetters) {     getters.someOtherGetter // -> 'foo/someOtherGetter'     rootGetters.someOtherGetter // -> 'someOtherGetter'    },    someOtherGetter: state => { ... }   },

  actions: {    // dispatch and commit are also localized for this module    // they will accept root option for the root dispatch/commit    someAction ({ dispatch, commit, getters, rootGetters }) {     getters.someGetter // -> 'foo/someGetter'     rootGetters.someGetter // -> 'someGetter'

    dispatch('someOtherAction') // -> 'foo/someOtherAction'     dispatch('someOtherAction', null, { root: true }) // -> 'someOtherAction'

    commit('someMutation') // -> 'foo/someMutation'     commit('someMutation', null, { root: true }) // -> 'someMutation'    },    someOtherAction (ctx, payload) { ... }   }  } }

Register Global Action in Namespaced Modules

If you want to register global actions in namespaced modules, you can mark it with root: true and place the action definition to function handler. For example:

{
 actions: {
  someOtherAction ({dispatch}) {
   dispatch('someAction')
  }
 },
 modules: {
  foo: {
   namespaced: true,

   actions: {     someAction: {      root: true,      handler (namespacedContext, payload) { ... } // -> 'someAction'     }    }   }  } }

Binding Helpers with Namespace

When binding a namespaced module to components with the mapStatemapGettersmapActionsand mapMutations helpers, it can get a bit verbose:

computed: {
 ...mapState({
  a: state => state.some.nested.module.a,
  b: state => state.some.nested.module.b
 })
},
methods: {
 ...mapActions([
  'some/nested/module/foo', // -> this'some/nested/module/foo'
  'some/nested/module/bar' // -> this'some/nested/module/bar'
 ])
}

In such cases, you can pass the module namespace string as the first argument to the helpers so that all bindings are done using that module as the context. The above can be simplified to:

computed: {
 ...mapState('some/nested/module', {
  a: state => state.a,
  b: state => state.b
 })
},
methods: {
 ...mapActions('some/nested/module', [
  'foo', // -> this.foo()
  'bar' // -> this.bar()
 ])
}

Furthermore, you can create namespaced helpers by using createNamespacedHelpers. It returns an object having new component binding helpers that are bound with the given namespace value:

import { createNamespacedHelpers } from 'vuex'

const { mapState, mapActions } = createNamespacedHelpers('some/nested/module')

export default {  computed: {   // look up in some/nested/module   ...mapState({    a: state => state.a,    b: state => state.b   })  },  methods: {   // look up in some/nested/module   ...mapActions([    'foo',    'bar'   ])  } }

Caveat for Plugin Developers

You may care about unpredictable namespacing for your modules when you create a plugin that provides the modules and let users add them to a Vuex store. Your modules will be also namespaced if the plugin users add your modules under a namespaced module. To adapt this situation, you may need to receive a namespace value via your plugin option:

// get namespace value via plugin option
// and returns Vuex plugin function
export function createPlugin (options = {}) {
 return function (store) {
  // add namespace to plugin module's types
  const namespace = options.namespace || ''
  store.dispatch(namespace + 'pluginAction')
 }
}

Dynamic Module Registration

You can register a module after the store has been created with the store.registerModule method:

// register a module myModule
store.registerModule('myModule', {
 // ...
})

// register a nested module nested/myModule store.registerModule(['nested', 'myModule'], {  // ... })

The module's state will be exposed as store.state.myModule and store.state.nested.myModule.

Dynamic module registration makes it possible for other Vue plugins to also leverage Vuex for state management by attaching a module to the application's store. For example, the vuex-router-synclibrary integrates vue-router with vuex by managing the application's route state in a dynamically attached module.

You can also remove a dynamically registered module with store.unregisterModule(moduleName). Note you cannot remove static modules (declared at store creation) with this method.

Preserving state

It may be likely that you want to preserve the previous state when registering a new module, such as preserving state from a Server Side Rendered app. You can achieve this with preserveState option: store.registerModule('a', module, { preserveState: true })

When you set preserveState: true, the module is registered, actions, mutations and getters are added to the store, but the state not. It's assumed that your store state already contains state for that module and you don't want to overwrite it.

Module Reuse

Sometimes we may need to create multiple instances of a module, for example:

  • Creating multiple stores that use the same module (e.g. To avoid stateful singletons in the SSR when the runInNewContext option is false or 'once');
  • Register the same module multiple times in the same store.

If we use a plain object to declare the state of the module, then that state object will be shared by reference and cause cross store/module state pollution when it's mutated.

This is actually the exact same problem with data inside Vue components. So the solution is also the same - use a function for declaring module state (supported in 2.3.0+):

const MyReusableModule = {
 state () {
  return {
   foo: 'bar'
  }
 },
 // mutations, actions, getters...
}

Thanks for reading. If you liked this post, share it with all of your programming buddies!

Further reading

A beginners guide to Vuex

Getting Started with Vuex: Managing State in Vue.js

Quick Intro to Vuex ORM 

How to use Vuex and Redux in your apps?

Vuex Crash Course | State Management


This post was originally published here

vue-js javascript web-development

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Top Vue.js Developers in USA

Vue.js is an extensively popular JavaScript framework with which you can create powerful as well as interactive interfaces. Vue.js is the best framework when it comes to building a single web and mobile apps.

Hire Web Developer

Looking for an attractive & user-friendly web developer? HourlyDeveloper.io, a leading web, and mobile app development company, offers web developers for hire through flexible engagement models. You can **[Hire Web...

Hire Node.JS Developers | Skenix Infotech

We are providing robust Node.JS Development Services with expert Node.js Developers. Get affordable Node.JS Web Development services from Skenix Infotech.