In this tutorial, we are going to be adding Vuex to our VueJS application. We’ll be looking at how we can improve the performance of our application and persist data between route changes.
Why Vuex?
Vuex is a state management pattern + library for Vue.js applications. Essentially, it acts as a centralized store for all components in an application.
Vuex Core Concepts
Before we continue to flesh out our VueJS application, we should really ground
ourselves with the core concepts of Vuex. There are 5 main concepts we’ll need
to get our heads round, state, getters, mutations, actions, and
modules.
- State : Our
statecontains everything we wish to store within ourVue.jsapplication. - Actions : Actions are what we call to interact with our state, these trigger
mutationswhich in turn do any modifications necessary to ourstate. - Mutations : These perform the act of updating our applications
state, they are triggered byactions. - Getters : These are functions that return commonly computed results. Say for
example you wanted to filter our list of articles to only show those with a
score above
100. You could define agetteronce that would do just that. This result is then cached until the data it relies upon is changed and usinggettersare a good way to improve application performance. - Modules :
modulesallow us to split our more complex application’s state into a series of smaller components, thus simplifying our state.
Installing Vuex
First things first, we will have to install vuex using our package manager of
choice. As I’ve been using yarn for this series, I’ll be using yarn to install
this package.
## npm
$ npm install vuex
## Yarn
$ yarn add vuex
Once we have successfully installed vuex we can go ahead and start using this
wonderful package.
Setting up a Store
The first thing we need to do is to create a new directory /src/store.js. This
will contain the code for our store that our application will rely upon.
Let’s create a new file index.js within this directory. In this file we will
be creating a store object that will be of type Vuex.Store({}). Within this
object we are going to define a state property as well as a mutations
property.
Within our state property we will store all of our application’s cached
articles and comments.
import Vuex from "vuex";
import Vue from "vue";
export const store = new Vuex.Store({
state: {
articles: []
},
mutations: {}
});
Now that we’ve set this up, we need to ensure that we call Vue.use(Vuex) to
explicitly install Vuex into our HackerNews application. We can do this just
below our import statements:
import Vuex from "vuex";
import Vue from "vue";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
articles: []
},
mutations: {}
});
It should be noted that whilst we are storing everything in the one file for now, it’s typically recommended to split your
mutations, youractionsand any modules you may have into separate files and directories. Check out the official docs for more on this.
Updating our main.js File
Now that we’ve created our basic vuex store, we need to ensure our Vue instance
is using this newly defined store by adding it to our root instance in our
main.js file:
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import router from "./router";
Vue.config.productionTip = false;
new Vue({
router,
store: store,
render: h => h(App)
}).$mount("#app");
Vuex Basics
Now that we’ve set up our application to use our newly defined store, let’s test
to see if it all works. Open your Home.vue component file and then within your
created: function() block, add:
console.log(this.$store.state.articles);
Now, when you refresh your page, you should see an empty array print out in the console. We’ve been able to successfully create a store, and then query said store from a component within our applicatiostoren.
Currently, this doesn’t really provide much extra value on top of what we
already have. Let us change this now by adding a few actions to our store.
These will actually perform the API requests needed to retrieve all articles and
comments etc.
Create a new file, actions.js within your /src/store/ directory. This is
where we will define our vuex actions.
Updating our State
We want to store both our topStories and our newStories, so we will need to
not only update our /src/store/index.js to import the mutations file we will
be creating in the next section and we will need to update our state object to
contain an array of topStories and newStories.
import Vuex from "vuex";
import Vue from "vue";
import actions from "./actions.js";
import mutations from "./mutations.js";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
topStories: [],
newStories: []
},
mutations,
actions
});
Defining our Mutations
We need to define a mutation that will update our state’s topStories and
newStories arrays. These will simply take in an article and push said article
to the respective array depending on what mutation was called. Create a new
file called /src/store/mutations.js and then add the following:
export default {
APPEND_TOP_STORY: (state, article) => {
state.topStories.push(article);
},
APPEND_NEW_STORY: (state, article) => {
state.newStories.push(article);
}
};
Defining our Actions
Now that we’ve defined our mutations, we need to add our actions that will use
these mutations. We’ll call these fetch_top_stories and fetch_new_stories
respectively. These will simply hit the appropriate API endpoints and then
commit the retrieves stories to our store.
import axios from "axios";
export default {
fetch_top_stories: ({ commit }) => {
axios
.get("https://hacker-news.firebaseio.com/v0/topstories.json")
.then(resp => {
let results = resp.data.slice(0, 25);
results.forEach(element => {
axios
.get(
"https://hacker-news.firebaseio.com/v0/item/" + element + ".json"
)
.then(result => {
commit("APPEND_TOP_STORY", result);
})
.catch(err => {
console.log(err);
});
});
})
.catch(err => {
console.log(err);
});
},
fetch_new_stories: ({ commit }) => {
axios
.get("https://hacker-news.firebaseio.com/v0/newstories.json")
.then(resp => {
let results = resp.data.slice(0, 25);
results.forEach(element => {
axios
.get(
"https://hacker-news.firebaseio.com/v0/item/" + element + ".json"
)
.then(result => {
commit("APPEND_NEW_STORY", result);
})
.catch(err => {
console.log(err);
});
});
})
.catch(err => {
console.log(err);
});
}
};
Updating our Homepage.vue and our New.vue Components
Now that we’ve defined everything we need with regards to our actions,
mutations and store, it’s time to update our Home.vue and New.vue
components so that they retrieve the topStories from the store or trigger a
fetch_top/new_stories action should the store not contain any stories.
New.vue component
data: function () {
return {
err: '',
stories: this.$store.state.newStories
}
},
created: function () {
if (this.$store.state.newStories.length === 0) this.$store.dispatch('fetch_new_stories')
}
Homepage.vue component
data: function () {
return {
err: '',
stories: this.$store.state.topStories
}
},
created: function () {
if (this.$store.state.topStories.length === 0) this.$store.dispatch('fetch_top_stories')
}
Hopefully, you will agree, that by moving off our state management code into
vuex, we have managed to greatly simplify some of our components.
Conclusion
In this section of the course, we managed to add Vuex to our HackerNews clone application. This helped to improve the performance of our application by caching API results in a simple store so that we don’t have to make a series of new API requests every time we navigate to a page we have already visited.
I would recommend looking at the official HackerNews project in order to look at how you can do things such as cache refreshing every 5 minutes and
Hopefully, you found this enjoyable and educational! In the next part of this series, we are going to be looking at how you can build your VueJS application so that it’s ready for deployment to production!