Vuex is a simple state management library for Vue js. It is very easy to use. 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.

Install Vuex

npm install vuex --save

Initialize Vuex

import Vue from 'vue'

import Vuex from 'vuex' Vue.use(Vuex)

Store

Time to build a store. Les goooo

Create a store

export default new Vuex.Store({

state:{

// Current state of the application lies here.

},

getters:{

// Compute derived state based on the current state. More like computed property.

},

mutations:{

// Mutate the current state

},

actions:{

// Get data from server and send that to mutations to mutate the current state

}

}) // You can assign a store to variable and export

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

// Import the store

import { store } from '/path/to/file'

State

First thing in the store is state

state:{

name:'Alicia Vikander',

age:20,

dob:'20/08/1990'

}

In vuex the single source of truth is the store. So let's hear a truth from the store.

Access State

Accessing a state is simpler than every other library

You can read the state directly like 👇

store.state.name // Alicia Vikander

But don’t MUTATE the state like 👇

store.state.name = 'NOOOOOOO'

This will get the work done but in long run, you won’t know which component changed the truth so this makes difficult to debug and track.

So let's see how to do

Import a helper function mapState from vuex. This will create a computed getter function for us. Then spread the mapState object with the name of the properties you want to access into computed properties of the component.

If you don’t want to change the name of the property then go with this 👇

computed:{

...mapState(['name', 'age', 'dob'])

// Now you can read the name by using this.name

}

But if you want to change the name then you have to use an object like notation

computed:{

...mapState({

userName : state => state.name,

userAge: state => state.age,

userDob: state => state.dob

})

// Now you can read the name by using this.userName

}

Finally, the component looks like this 👇

<template>

<div>

Name: {{ name }}

Age: {{ age }}

Dob: {{ dob }}

</div>

</template> <script> import { mapState } from 'vuex' export default {

name:'Profile',

computed:{

...mapState(['name', 'age', 'dob'])

// Now you can read the name by using this.name

}

}

</script>

Now we can use `this.age` to access the truth from the store.

But again we can’t mutate the state like `this.age=this.age+1`

So the question is why not? Let's see

You have no rights to change someone’s property even if you have them. So let's ask them to do. Let's ask here 👇

Mutation

Mutation is the only object which has a proper right to mutate the state.

Mutation looks like this 👇

updateName(state, name){

state.name = name

}

A mutation may have two arguments as state and payload.

State has the current state of an application.

Payload is an optional one, which will give the data to mutate.

So after adding mutation, the store look like this 👇

import Vue from 'vue'

import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({

state:{

name:'Alicia Vikander',

age:20,

dob:'20/08/1990'

},

mutations:{

updateName(state, name){

state.name = name

}

}

})

Invoke Mutation

If we have the reference to store object then we can call the mutation directly like these.

store.commit('updateName','Alicia')

Object-Style Commit

store.commit({

type: 'updateName',

name: 'Alicia'

})

We will use the store.commit() notation in a router and inside the store but in components, we have another way to invoke mutation

Inside a component, we will Import a helper function ‘mapMutations’ from vuex and spread that into methods to invoke a mutation

methods:{

...mapMutations(['updateName'])

}

// Now this.updateName('Alicia') will call the mutation in the store and update the state.

If you want to change the name then 👇

methods:{

...mapMutations({

editName: 'updateName'

})

}

// Now this.editName('Alicia') will call the mutation in the store and update the state.

Now the component looks like this 👇

<template>

<div>

Name: {{ name }}

Age: {{ age }}

Dob: {{ dob }}

</div>

</template> <script> import { mapState, mapMutations } from 'vuex' export default {

name:'Profile',

computed:{

...mapState(['name','age','dob'])

},

methods:{

...mapMutations(['updateName'])

}

} </script>

But “Mutations Must Be Synchronous” So If you want data from sever then you have to create actions.

Actions

Actions can contain arbitrary asynchronous operations, action commits mutation after doing the asynchronous operation.

For instance, if you want user data before rendering then you have to call the action.

What actions will do

Request the server for user data Receive response from the server and if data exists then mutate the state else throw an error After mutating the state the components associated with that state will be re-rendered by vue instance.

Action has two arguments context and payload

context has the reference for a store.

To mutate the state use context.mutate(‘updateName’ , ‘Alicia’ ) .

To read a state ‘context.state.name’.

The payload is the optional one, which will carry optional data to do actions.



// Get the data from server

axios.get('

// commit to the store to mutate the state

context.commit('loadUserData',response)

})

}

getUserData(context,payload){// Get the data from serveraxios.get(' www.api.yourdomain').then((response)= >{// commit to the store to mutate the statecontext.commit('loadUserData',response)})

After adding actions to store 👇

import Vue from 'vue'

import Vuex from 'vuex' Vue.use(Vuex)

state:{

name:'Alicia Vikander',

age:20,

dob:'20/08/1990'

},

mutations:{

updateName(state, name) => {

state.name = name

},

loadUserData(state,payload){

state.name = payload.name;

state.age = payload.age;

state.dob = payload.dob;

}

},

actions: {

getUserData(context,payload){

// Get the data from server

axios.get('www.api.yourdomain').then((response)=>{

// commit to the store

context.commit('loadUserData',response)

})

}

}) export default new Vuex.Store({state:{name:'Alicia Vikander',age:20,dob:'20/08/1990'},mutations:{updateName(state, name) => {state.name = name},loadUserData(state,payload){state.name = payload.name;state.age = payload.age;state.dob = payload.dob;},})

Access actions

If you have reference to store then dispatch an action using 👇

store.dispatch('nameOfAction');

Inside the store and router, we use this method. In components we may use mapActions helper functions

<template>

<div>

Name: {{ name }}

Age: {{ age }}

Dob: {{ dob }}

</div>

</template>

<script>

import { mapState, mapMutations, mapActions } from 'vuex'

export default {

name:'Profile',

computed:{

...mapState(['name','age','dob'])

},

methods:{

...mapMutations(['updateName']),

...mapActions(['getUserData'])

}

}

</script>

Now we can use this.getUserData() to dispatch an action

Getters

We need some computed functions in all components So we define all those functions inside this getters. Every function inside getters computes derived state based on store state.

It has two arguments state and getters

The state has current state values

getters are optional, all other getters can be used inside one getter function

getters:{

isAdult(state,getters){

return state.age >=18 ? true : false

}

}

Call getters

store.getters.isAdult;

Inside components use mapGetters helper function and spread that into the computed property.

<template>

<div>

Name: {{ name }}

Age: {{ age }}

Dob: {{ dob }}

</div>

</template>

<script>

import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'

export default {

name:'Profile',

computed:{

...mapState(['name','age','dob'])

...mapGetters(['isAdult'])

},

methods:{

...mapMutations(['updateName']),

...mapActions(['getUserData'])

}

}

</script

Now you can access the getter by this.isAdult

PS: mapMutations, mapActions have to be inside methods, and mapState, mapGetters have to be inside a computed property.

Computed

And If you have to change the computed property then you can use a set function for computed property

computed: {

name: {

// getter

get: () => {

return this.$store.name

},

// setter

set: (newValue) => {

this.$store.dispatch('updateName',newValue)

}

}

}

When you try to mutate the computed property then you will get an error saying no setter function is available for that computed property. So if you want to mutate the computed property then write a set function.