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”:
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.
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:
- Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store’s state changes.
- 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