Structuring store with the right feet using vue/vuex
Tags: vue, javascript, codenewbie
Published: 2019-09-30 14:25:02

_This publication will be focused on how to structure our store in a simple and effective way. I will be assuming that you have a fairly reasonable knowledge using the vue framework and the handling of Lifecycle Hooks_

## What is Vuex?
_Vuex is a state management pattern based on the singleton architecture that allows us to have centralized and accessible data in any component within the application but without being able to be modified without some control._

## Why should we use Vuex?
_By using a centralized application data store, the complete state of the application can be represented in one place, which makes the application more organized. By using a unidirectional data flow, mutations and access to the data of the scope component only to the required data, it becomes much simpler to reason about the role of the component and how it should affect the state of the application._

## Store structure
### store.js
_It is better to keep all the Vuex logic in a separate file. We will keep our logic in a file called `store.js`. In our `store.js` file we have a store object that is our Vuex store._

_The store is an instance of the `Vuex.store` object, which consists of four objects. The four objects are the `state`, `actions`, `mutations` and `getters`.
Since these objects have been defined in different files, they must be imported into the `store.js` file and then passed in the store instance._

```javascript
import Vue from 'vue';
import Vuex from 'vuex';
import {state} from './state';
import {actions} from './actions';
import {mutations} from './mutations';
import {getters} from './getters'; 

Vue.use(Vuex);
export default new Vuex.Store({
  state,
  mutations,
  actions,
  getters
});
```

### state.js
_The state is an object that contains the state of the application data._

```javascript
export const state = {
  data: [],
  isLoading: true
};
```

### mutations.js
_**Mutations** is also an object that contains methods that affect the state and only care to control the states, to manipulate it._

_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._

```javascript
export const mutations = {
   SET_DATA(state , payload){
     state.data = payload;  
   },
   IS_LOADING(state , payload){
     state.isLoading = payload;
   }
 };
```

### actions.js
_**Actions** are methods used to cause mutations and execute asynchronous code. Responsible for preparing everything necessary for a mutation to confirm a change in the state._

_The actions expect a promise to be resolved, hence we make a return of the promise that returns `axios`. When `axios` returns the data, we can execute commits with the type of mutation that we want to carry out. Instead of mutating the state, actions commit mutations, in this case, using the mutator `SET_DATA`. And the mutator `IS_LOADING` that will help to know if there is still data to load._

```javascript
import axios from 'axios';
const BASE_API_URL= '...';
const API_URL_ENDPOINT = '...';
const A = axios.create({ baseURL: String(BASE_API_URL) });
export const actions = {
  GET_DATA({commit}){
    A.get(API_URL_ENDPOINT).then((res) =>{
      commit('SET_DATA' , res.data);
      commit('IS_LOADING' , false);
    }).catch((err) =>{
      console.error(err)
    });
  }
};
```

### getters.js
_**Getters** contain the methods used to abstract access to the state and to do some preprocessing tasks, if necessary (data calculation, filtering, etc …)._

_Vuex allows us to define "getters" in the store. 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._

- _**Getters** will receive the state as their 1st argument_

_For the following example, we will be using `Lodash's` library. `Lodash` is a well-known JavaScript utility library that makes it easy to manipulate arrays and objects, as well as functions, strings, etc._

_So, since we are interested in filtering some data in particular, we will use the function `_.filter()`._

## _.filter(collection, [predicate=_.identity])
_Iterates over elements of `collection`, returning an array of all elements `predicate` returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection)._


```javascript
var _ = require('lodash');
export const getters = {
  FILTER_SPESIFIC_DATA: (state) =>{
    return _.filter(state.data , (data) =>{
      // ....
    });
  }
};
```

## Working in the view folder
### Home.vue
- _When a component needs to make use of multiple store state properties or getters, declaring all these computed properties can get repetitive and verbose. To deal with this we can make use of the `mapState` helper which generates computed getter functions for us._

- _The easy way to access getters in your component, however, is through Vuex's `mapGetter` helper method. This allows you to mount getters to top-level computed properties in your component._

_Note that `mapState` returns an object. How do we use it in combination with other local computed properties? Normally, we'd have to use a utility to merge multiple objects into one so that we can pass the final object to `computed`. However with the [object spread operator](https://github.com/tc39/proposal-object-rest-spread) (which is a stage-4 ECMAScript proposal), we can greatly simplify the syntax, equally applies with `mapGetters`._

### Spread Properties
_Spread properties in object initializers copies own enumerable properties from a provided object onto the newly created object._

```javascript
<template>
  <div class="content">
    <div v-if="isLoading"> loading...</div>
    <div v-else>
       <div v-for="(content , index) in data" :key="index">
         // ....
       </div>
    </div> 
  </div>
</template>
<script>
  import {mapState , mapGetters} from 'vuex';
  import store from '../store/store.js';
   
  export default{
    name: 'home',
    computed:{
      ...mapState(['data' , 'isLoading']),
      ...mapGetters(['FILTER_SPESIFIC_DATA']),
      filteredDataObj(){
        return FILTER_SPESIFIC_DATA()
      }
    },
    created(){
      store.dispatch('GET_DATA')
    }
  };
</script>
<style scoped>
  .content{
    ....
  }
</style>
```

## Finally…..

### main.js
_Now, to access the store you'll either have to import it in all of your components, or you can inject it into the root Vue instance to have it automatically injected into every other component in your app as `this.$store` or importing the `store.js` file from the store folder._

```javacript
import Vue from 'vue';
import Vuex from 'vuex';
import App from 'App.vue';
import { store } from '../store/store.js';
Vue.config.productionTip = false;
Vue.use(Vuex);
new Vue({
  store,
  render: h => h(App)
}).$mount('#app');
```

## Conclusion
_Keep in mind that vuex helps us maintain and test our application better, but we also have to be aware that vuex involves new levels of abstraction that will make us need to work with new concepts that will make the learning curve less accessible for developed juniors to our projects. So be careful._

## References
[The Progressive JavaScript Framework](https://vuejs.org/)

I'll be glad that you like this article! 💖