State Management in Vue using Vuex

State Management in Vue using Vuex

12 March 2021

Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion. It also integrates with Vue’s official devtools extension to provide advanced features such as zero-config time-travel debugging and state snapshot export / import.

This is a simple representation of the concept of “one-way data flow”:

State_Management_in_Vue_using_Vuex_01

Multiple components that share a common state:

  • Multiple views may depend on the same piece of state.
  • Actions from different views may need to mutate the same piece of state.

This is the basic idea behind Vuex, inspired by Flux , Redux and The Elm Architecture. Unlike the other patterns, Vuex is also a library implementation tailored specifically for Vue.js to take advantage of its granular reactivity system for efficient updates.

State_Management_in_Vue_using_Vuex_02

Installation

CDN: Unpkg.com provides NPM-based CDN links. The above link will always point to the latest release on NPM. You can also use a specific version/tag via URLs like https://unpkg.com/vuex@2.0.0.

Include vuex after Vue and it will install itself automatically:

<script src="/path/to/vue.js"></script>

<script src="/path/to/vuex.js"></script>

NPM: npm install vuex –save

Yarn: yarn add vuex

Install Vuex as a plugin in a module system:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

At the center of every Vuex application is the store. A “store” is basically a container that holds your application state. There are two things that make a Vuex store different from a plain global object:

  1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store’s state changes.
  2. You cannot directly mutate the store’s state. The only way to change a store’s state is by explicitly committing mutations. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications.

Simple Example:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

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

Now, you can access the state object as store.state, and trigger a state change with the store.commit method:

store.commit('increment')
console.log(store.state.count) // -> 1

Getting Vuex State into Vue Components

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }
}

Whenever store.state.count changes, it will cause the computed property to re-evaluate, and trigger associated DOM updates.

Getters:

Vuex allows us to define “getters” in the store. You can think of them as computed properties for stores. Like computed properties, a getter’s result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.

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

Mutations

The only way to actually change state in a Vuex store is by committing a mutation.

const store = new Vuex.Store({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // mutate state
      state.count++
    }
  }
})
store.commit('increment')

You can pass an additional argument to store.commit, which is called the payload for the mutation:

Actions

Actions are similar to mutations, the differences being that:

  • Instead of mutating the state, actions commit mutations.
  • Actions can contain arbitrary asynchronous operations.
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
})
actions: {
  increment ({ commit }) {
    commit('increment')
  }
}

Modules

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

search
Blog Categories
Request a quote