Add Simple State Management with Vuex
Tags: webdev, programming, javascript, vue
Published: 2021-01-26 01:15:42

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

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 Vuex to our app and add a simple store.

What is Vuex?
=============

Vuex is for storing states that are needed by multiple components in one central location.

![https://thewebdev.info/wp-content/uploads/2020/06/vuex.png](https://thewebdev.info/wp-content/uploads/2020/06/vuex.png)

It lets us get and set shared state and propagate any changes made to the shared state automatically to all components.

In the workflow diagram above, we can see that Vuex mutations are committed by our code when we get something from the back end API.

The mutation will update the state with the back end API data and the state will be updated in our Vue components.

We can also dispatch mutations from Vue components to change the Vuex store state the change will be propagated to all components that have access to the store.

Getting Started
===============

We can include Vuex with a `script` tag in our HTML code:

```
<script src="https://unpkg.com/vuex"></script>
```

Then we can create a simple store by using the `Vuex.Store` as follows:

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

The code above is a store which stores the state `count` .

Then we can commit the `increase` mutation by running:

```
store.commit("increase");
```

Then we can get the state after the mutation is done by running:

```
console.log(store.state.count);
```

`store.state.count` is the `count` state from the Vuex store. Then we should see 1 logged.

Getting Vuex State into Vue Components
======================================

We can get the state into our store by adding a computed property.

Therefore, to add the state into our store, we can write the following:

`index.js` :

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

new Vue({  
  el: "#app",  
  computed: {  
    count() {  
      return store.state.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">  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
```

Then we should see 0 displayed since `count` is 0 initially in the `store` .

Then whenever `store.state.count` updates, the computed property will be updated and the view will update with the new value.

A more convenient way to inject the store into all child components is to add the `store` in the root component as follows:

`index.js` :

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

new Vue({  
  el: "#app",  
  store  
});
```

`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">  
      <p>{{$store.state.count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
```

Then it’ll be available to all child components and we don’t have to worry about add computed properties for every value.

It works with child component without much changes:

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

Vue.component("counter", {  
  template: `<div>{{ count }}</div>`,  
  computed: {  
    count() {  
      return this.$store.state.count;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store  
});
```

`this.$store` is available to the `counter` component just by including it in the root Vue component.

The mapState Helper
===================

To avoid adding a new computed property for every state that’s in the store, we can use the `mapState` helper to add it. For example, we can write the following code to do that:

`index.js` :

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

Vue.component("counter", {  
  data() {  
    return {  
      localCount: 1  
    };  
  },  
  template: `  
    <div>  
      <div>{{ count }}</div>  
      <div>{{ countAlias }}</div>  
      <div>{{ countPlusLocal }}</div>  
    </div>  
  `,  
  computed: Vuex.mapState({  
    count: state => state.count,  
    countAlias: "count",  
    countPlusLocal(state) {  
      return state.count + this.localCount;  
    }  
  })  
});

new Vue({  
  el: "#app",  
  store  
});
```

`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">  
      <counter></counter>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>
```

Then we see:

```
001
```

Because we called `mapState` as follows:

```
computed: Vuex.mapState({  
  count: state => state.count,  
  countAlias: "count",  
  countPlusLocal(state) {  
    return state.count + this.localCount;  
  }  
})
```

We have:

```
count: state => state.count,
```

which gets the `count` state from the store and returns it. The `count` is 0 so we get 0.

Then we have:

```
countAlias: "count"
```

which is a shorthand for:

```
count: state => state.count
```

And finally, we have:

```
countPlusLocal(state) {  
  return state.count + this.localCount;  
}
```

which adds `state.count` from the store to `this.localCount` , which we set to 1.

Object Spread Operator
======================

We can combine local computed properties with `mapState` by applying the spread operator to `mapState` as follows:

`index.js` :

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

Vue.component("counter", {  
  data() {  
    return {  
      localCount: 1  
    };  
  },  
  template: `  
    <div>  
      <div>{{ count }}</div>  
      <div>{{ foo }}</div>        
    </div>  
  `,  
  computed: {  
    foo() {  
      return 2;  
    },  
    ...Vuex.mapState({  
      count: "count"  
    })  
  }  
});

new Vue({  
  el: "#app",  
  store  
});
```

Then we get:

```
02
```

displayed since `foo` always returns 2.

Components Can Still Have Local State
=====================================

Components can still have their own local state, so we don’t have to put everything in the Vuex store.

Conclusion
==========

We can add a Vuex store to our app to store the states of our app that are shared by multiple components.

To make getting state easy, we can include the store in the root Vue component.

Then we call the `mapState` helper to get the states we want in any component.

We can also combine it with the local states with the spread operator in the `computed` object.