# Data store

# What is Vuex ?

TIP

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

# Vuex - presentation


# Start from here

First we have to add the vuex library. Click on the "Add Dependency", search for vuex and select the first one.

Open the main.js file, import and use vuex. Create an empty vuex store and let vue know that it will use the store

//main.js
import Vuex from 'vuex'
Vue.use(Vuex)

var store = new Vuex.Store({
    state: {},
    mutations: {},
    actions: {}
})

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount("#app");

It is time to define the state of the store. Our store will mainly contain the data that is present on the podcasts and the podcast components. The way we'll implement it is by moving the ajax calls from the components to the store.

Defining the store simply by replaceing the existing var store =with the new one:

//main.js
var store = new Vuex.Store({
state: {
    first: false,
    last: false,
    page: 1,
    podcasts: [],
    podcast: null
},
mutations: {
    LOAD_PODCASTS(state , data) {     
    state.podcasts = data.shows;
    state.first = data.first;
    state.last = data.last;
    }
},
actions: {
    loadPodcasts({ commit, state }) {
        axios
        .get(`https://jsnoise.herokuapp.com/api/showslist?page=${state.page}`)
        .then(response => {
            console.log("vuex podcasts:", { data: response.data });
            commit("LOAD_PODCASTS", response.data);
        })
        .catch(err => console.dir(err));
    },
    prevPage({commit, state,dispatch}) {
        if (state.first == true) return;
        state.page--;
        dispatch("loadPodcasts");
    },
    nextPage({commit, state,dispatch}) {
        if (state.last == true) return;
        state.page++;
        dispatch("loadPodcasts");
    }
    }
});

The store now has some state that contains the podcasts list, the podcast that will be displayed in the detail page, the current page and first/last bool properties. This data will be made available in the components simply by using mapState and mapActions. The mutation is the only one that is allowed to change the state while the actions are called from components to execute modification to the state through mutations. The actions are allowed to make complex logic and also to make calls to external resources.

The loadPodcasts code is the method that we moved from the podcasts component and updated the then code to to just commit the LOAD_PODCASTS mutation.

It is time now to move to the Podcasts.vue component and do some updates

First update is to make some imports in the script tag:

//Podcasts.vue
import {mapState, mapActions } from "vuex";

mapState and mapActions will make the bridge between the vuex store and our component. Remove the full data() method and add a computed property inside the podcasts component just after the name:

//Podcasts.vue
computed:{ ...mapState(["last", "first","podcasts"])},

This line will make the last, first and podcasts available on this. Now instead of the podcasts from the data of the component we are able to use the podcasts from the vuex store just by using the mapState. The property podcasts will be updated and pushed to all the components that uses it. So every time it is changed the components using it will know and they will re render the part of the page that contains it.

Next we will remove all the properties from the data() block except page:1 and we'll replace the full methods block with this new one:

//Podcasts.vue
methods: {
    ...mapActions(["loadPodcasts","prevPage","nextPage"]),
    randomPic: function() {
    let pic = "images/img_" + (Math.round(Math.random() * 4) + 1) + ".jpg";
    return pic;
    }
}

As we can see the methods block will only contain map actions defined in the store. The way mapActions works is simply by adding to this the specified actions from the store.

Since we have the podcasts part let's add the mutation and action for loading details for a single podcast.

Inside the main.js file, in the vuex store, we'll add one mutation and one action. The mutation LOAD_PODCAST will save the podcast data into the state and the action loadPodcast will make the call to the server to get the podcast details based on the ID.

Update the vuex store with the new action:

//main.js
,
loadPodcast({ commit }, showId) {
axios
    .get(`https://jsnoise.herokuapp.com/api/shows/${showId}`)
    .then(response => {
    console.log("vuex podcast:", { data: response.data });
    commit("LOAD_PODCAST", response.data);
    })
    .catch(err => console.dir(err));
}

Update the vuex store with the new mutation:

//main.js
,
LOAD_PODCAST(state, data) {
    state.podcast = data;
}  

It is time to make the podcast component know about and use the vuex store.

Open the Podcast.vue component and remove the loadPodcast() and the data() methods. Next we have to import the mapState and mapActions from vuex. Above the export default { add the following line:

//Podcast.vue
import {mapState, mapActions } from "vuex";

The above line will make mapState and mapActions available to the component so that we can use them.

Above the methods part of the component add the computed property so that we can get the podcast that was selected in the previous page.

//Podcast.vue
computed:{...mapState(['podcast'])},

Remove the data() block from the component.

On the methods: block add using the spread operator the line that will allow the component to load the podcast based on the parameter received from the url into the store. The new methods block will look like this:

//Podcast.vue
methods: {
        ...mapActions(['loadPodcast'])
},

It only remains for the Podcast component to load the podcast once this page is displayed. We do this by ensuring only the following code is present in the created() method.

//Podcast.vue
this.loadPodcast(this.$route.params.id);

# Well done! you now have Flux architecture in place.

Next, let's replace the REST implementation with a GraphQL one.