Skip to content

How to Use Vuex and Vue-Router in a Vue.JS Project

I have been working on one of front end and have been spending a lot of time getting acquainted with and using Vue moving on from how to start a new project in Vue Js.

One of the many cool things I like about Vuex is Vue-Router in this post we will explore how to implement these in a project.

What is Vuex

Two the key aspects I have been learning about lately is about using Vuex and Router in a Vue Project and just why learning to use these is key and really helps to improve your development and site experience.

Vuex is a library that we can use with Vue.js to manage different states in an application. 

Vuex provides a centralized place to store all the pieces of data in our application. Whenever data changes, this new set of data will be stored in this centralized place. Also, all of the components that want to use that data will be fetched from the store. This means that we have a single source to store all the data, and all the components that we build will be able to access that data. 

One of the downsides to using a pre-rolled full stack web project template is that - in my experience anyway - they tend to abstract the use of Vuex and Router or worse bury it an less intuitive manner which makes it difficult to comprehend what is going on.

Key Vuex Terms

State: This is an object that contains the data. Vuex uses a single state tree, which means that it is a single object that contains all the pieces of data for the application.

Getters: It is used to fetch data from the state tree.

mutations: They are the methods that change the data in the state tree.

Actions: They are the functions that perform mutations.

Solution Overview

Many of the tutorials I found regarding Vuex and Router seemed to overly complex and often involving elements of projects that one will probably not be involved.

In this example we are going to implement Vuex and Vue-Router in a scenario that almost everyone will encounter in any project, Authentication and Authorization and making use of Json Web Tokens in this example we will be building on ASP.net Core 2.2 JWT Authentication but from a Vue.JS point of view we are actually going to be pretty agnostic where the JWT comes from as in essence it is only going to be from some API end point which we'll be calling using Axios.

I will also be using a MDB Vue Pro : Material design component framework which will simplify our mark-up. In how to start a new project in Vue Js I explain how to set this all up and to generate a project.

Installing Vuex and Vue-Router

If like me and you have generated your new Vue Project using the Progressive Web Application (PWA) template with the Vue-CLI then there is nothing more you need to do because they have already been pre-installed and all minimum configuration required to start making use of them has already been done, you can happily skip this section.

if you have not used the PWA template then you will more than likely need to add these packages to your project using:

Shell

This will add the packages so we can use them, but you will still need to register the packages within the application.

Create 2 new JavaScript files in your root source directory:

Shell

Add the following minimum required code to your router.js

JS

The default mode for vue-router is hash mode - it uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes.

To get rid of the hash, we can use the router's history mode, which leverages the history.pushState API to achieve URL navigation without a page reload.

For more information check out HTML5 History Mode for why I have chosen that and to understand the potential web server configuration you have to consider going forward.

Then add the following code to your store.js

JS

We can now add references to these files in our main application file, so in your main.js or app.js import the files and add them you Vue Instance.

JS

By providing the store option to the root instance, the store will be injected into all child components of the root and will be available on them as this.$store, later on in this article we'll see why this is important.

One notable difference to my particular implementation is that I will be making use of ,MDB Vue : A Material Design Component for Vue Pro to make my styling and layout easier so therefore I have imported the required references at the top.

Using Vue-Router

Making use of the Vue-Router is extremely easy all we have to do is basically create some web pages them to the router and then ensure we add router-view to our App.vue page and the pages will be displayed. However, in order for this to be achieved still requires a little bit of work.

Lets implement a very basic example, with out too much code so we don't get lost in the detail bearing in mind we are going to focus on Authentication and Authorisation perspective.

Lets create at least two more pages. I have a views folder in my project so I am going to create them there. The naming of these 3 views are give away for what they care going to be used for. One will be an About Us page which is publicly accessible and the other is going to be a Dashboard page which should only be accessible by a user which has successfully logged.

Shell

I am also going to create a re-usable component which will contain our Application header file, because this is a reusable component I am going to place it in a folder named components This is an arbitrary convention but when working on larger projects and teams it becomes important to clearly define the purpose of each of application components

Shell

In each of these files I am going to add the bear minimum mark up required at this stage to get them working.

HTML

With all our components now set up, lets crack on implement some code to get the basic router working.

First thing we're going to do is implement the Header file, primary reason why this is where we are going to store all the links to enable switching through the pages. For now we are going to keep it really simple.

I mentioned previously that I will be making use of MDB Vue Pro : Material Design Component Framework to make our styling and layout easy and professional . This also helps with keeping our code clean without getting lost in multitude of styling mark-up etc.

Our completed header file will look contain a brand logo and some links to pages within our application.

HTML
JS

You may notice that we're making use of binding syntax :to="{ name: 'home' }" which actually a short cut to using links contained in our router file.

Lets go ahead and define those routes within our router.js file.

JS

We have imported our pages and actually created the routes for them. Don't worry about how cumbersome this all looks at this stage, we are going to tidy this all up later. but for now we simply want to get basics of routing working just to illustrate how to make use of it simply. Once we get the basics right, we'll get into the more complex scenarios.

Lets just update each of Views now with some layout logic so we have something display. We'll keep it really simple and basically only put two columns with a header of name of the page.

HTML
JS

Our application is almost ready to run all we need to do now is edit our App.vue to all components to work together.

HTML
JS

We can now run our application and view the results in our browser. If you are using the the project created vue-cli then simply use npm serve or yard serve to do so.

The result will look something similar

We have implemented a really basic implementation of using the Vue Router and if we click on any of the links we can flick through our pages. This is great, but there are obviously a few little issues not least of which we want to be able to hide some of out pages for only authenticated users and for that we will also need to implement some kind of login functionality.

Implement Login page

Lets edit some of the mark up for our Login Page now. We'll add simple login features here or Email and Password functionality. We're going to keep it really simple and not have too much going on for now.

HTML
JS

if we view our page in the browser it will appear as follows.

We are now all set to get to the point of our application and we can now start making use of Vuex and get deeper involved with functionality of the router etc.

Create Database

This application is solely for demonstration purposes for now, so we don't want to go through the whole process of creating a database and API endpoint just to illustrate functionality. We are just going to use a simple Firebase database and API end point to get things moving quickly.

Firebase is Google's mobile platform that helps you quickly develop high-quality apps and grow your business. I am going to use Firebase as the back end as I don't want to get lost in the details of setting up and configuring a back end system using a programming language of yoru choice.

I won't walk you through the process of creating a Firebase end point, it's really simple and Google already provide great documentation explaining how its done.

I have simply create an application and have enabled Email/Password Authentication method. Although we are going to use Firebase as the back end we are also going to make use of the Firebase AUTH REST API end points which will simulate using any typical REST API end point for authentication.

That's it from a database set up point of view.

Set up Axios in Vue

Our primary mechanism for communicating with our Firebase database is going to be via REST API. So we will need to set up axios instance so we can communicate with it.

Lets add a new JavaScript file named axios-auth.js in a new directory we're going to call services. You will need to ensure you have a reference to the axios in your package.json if not simply add it as below

Shell

We'll add the following code to that file, we are going to add a reference to the base Url for the Google API's in this instance.

JS

We have now successfully configured our axios instance we going to use for our authentication purposes. Check out using environment variables in Vue.JS for an approach on how you could improve this code to remove the magic string but for the purpose of this tutorial the code will suffice.

Using Vuex

Vuex is a centralised state management tool for Vue. It gives you a central store that all of your components can access, update and react to changes. Unless you are doing a very simple (in functionality) Vue app, it is highly recommended you use Vuex for all of the management of your data and states.

Add Login logic to Vuex

We now start getting into the weeds of making use of Vuex, most notbably is that the state we want to track and mutate is the Logged in status of the user.

At the center of every Vuex application is the store. A "store" is basically a container that holds your application state. There are two things that make a Vuex store different from a plain global object:

  1. Vuex stores are reactive. When Vue components retrieve state from it, they will reactively and efficiently update if the store's state changes.
  2. You cannot directly mutate the store's state. The only way to change a store's state is by explicitly committing mutations. This ensures every state change leaves a track-able record, and enables tooling that helps us better understand our applications.

So when a user logs in, we want to be able to capture the details and session token so we can use it.

Lets add the following code to our store.js

JS

effectively what we doing here is creating some State want to track

  • tokenId
  • userId
  • user

We have also create an action which we will call to get the data which will in turn pass to the mutations to change the state.

At the moment, our action is not actually going to call the mutation and for the time being it is only going to log the response to the console so we can actually see the response the from Firebase.

I also wanted to illustrate how we call the store from our Login component. So lets update the code in the Login Component.

HTML
JS

It turns out calling our store within our code is really easy because we have taken the time to set up store as a global object we simply access using this.$store and the dispatch is mechanism for calling an action which we reference by name and we pass in the arguments.

If we run the cod now and inspect it using dev tools and inspecting the console we will see that Firebase correctly logs in our user and we get the details back.

This is great and we are successfully able to connect to API and login our user. However, at this stage we are not actually doing anything with this data.

lets take a look at the data that is passed back from the Firebase authentication which we may want to store for use in our application

Saving the token for reuse

It is at this point that most tutorials available on the net proceed to illustrate how to store the token in your browsers LocalStorage. We're not going to do that, instead I will tell you to read Please Stop Using Local Storage primarily because Randall Degges explains it a lot better than I could and reading the associated comments and discussion is great for developers to go through and get their heads around this complex topic.

I also wanted to take the opportunity to play with LocalForage and integrate it with Vuex.

Integrating LocalForage with Vuex

We need to install a new package to install a new package called vuex-persist

Shell

We also need to add the localForage package

Shell

Once installed we can now add it to our VueX store, we'll do by editing our store.js and importing

JS

We have configured our application to make localForage and we have defined a key which is the the name of our application so all entries we make will now conveniently be located in a key/value format.

The benefit of this approach is that we don't have to pepper our code with all manner of

JS

Every time we want to get or set an item in our local storage, which causes you to run into the risk introducing bugs and drift in your code and you'll lose track of which function has set a value.

Personally I hate reading code and trying to understand what is going on when the code is polluted and and everything is interwoven. Unfortunately JavaScript code just seems to lend itself to this kind of abuse.

The below code is an example of what I term as bad code and the developer just seems to have mashed up all sorts of madness in the code to get something working. The end result is, he might understand it today, but in a couple of weeks, or in my case a cup of coffee when he comes back to it won't be able to figure it out!

JS

Using the localForage approach we set an application state values they are persisted whichever local state database is available. Lets see that with an example

We are now going to slightly modify our store.js to enable retrieving our values from the response and commiting our values of interest to state. Which will in turn create an entry in whichever local database our browser supports.

JS

When we run the application again and login again and we use the Vue.js devtools Extension on our browser we can see the state has been saved

We can now also go check the Application tab of DevTools and expand the Storage node to inspect the IndexDb and check that our values we wanted to persist are there.

That's pretty cool! We have now persisted the values we need to maintain our state throughout our application, so we can now get those values across pages.

We're still not done yet! We still haven't handled how we can navigate to another restricted page and to actually hide that page in our navigation menu unless the user is logged in.

Restricting the Dashboard page

We are now going to refactor our app a little to actually protect the Dashboard page so we can't access it if we are not logged in. At the moment we could still access the page if we entered the Url into the address bar http://localhost:8080/dashboard thats no good, besides we also want to actually redirect the user there when they are logged in.

First, thing we need to do is edit our router.js file a little to add some additional functionality.

JS

You will notice a couple of things have changed. The first we have now imported our store file into the router so we can now access some functionality from it.

Then we seem to have added and additional meta attribute to the Dashboard route. This attribute enables us to associate some additional properties to routes for instance, routes requiring authentication, we add extra data to it to enable us identify it when the user tries to access it.

This is functionality that is provided by vue-router and is known as Navigation Guards which are primarily used to guard navigations either by redirecting it or canceling it.

There are a number of ways to hook into the route navigation process: globally, per-route, or in-component. Vue Router Navigation Guards

We have also attached an additional method to the router where by we do check on each route and we inspect the additional Meta attribute and if it exists we check to see if the user is logged in, by checking a Getters from our imported store.

Warning

This approach is still not secure and is only checking for the existing of a token. We are not validating the token or even checking what the contents are, just merely that a property that a token exists.

We will delve further into this in later tutorials. For now we will simply assume that the Getter returns a valid token.

We are also going to edit our store.js add the additional Getters and while we're at it we will slightly refactor our Login method and add a Log out method too!

JS

Basically what we have done, is if the user is login is successful we will redirect them to the Dashboard page.

The logout method simply calls out logout mutation to clear all the properties and redirect the user to the login page.

We now also want to make a slight refactor to our Header.vue component

HTML
JS

The most notable here is that we have added a conditional check to see if the user is Logged In and if they are display the Logout Link or Login if they aren't.

We have added Compute property and Method to handle this, and notice how we actually access the Store actions to handle these methods.

If we now run the app again we will be able to login in logout and if we try access the Dashboard page if we are logged out, we should be redirected to the login page.

Summary

This is as far as I want to take this example. Our app is not totally secure at this stage and there is still a few bugs, but at this stage we actually have a functioning Login/Logout functionality and we're using Vuex. Router and LocalForage to all work together to handle this.

If you enjoyed this article and would like to be notified when the follow up this is published or even would like to know when I publish more tutorials why not subscribe to my newsletter.

Alternatively use the comments below to let me know of any omissions or queries or even just to slag me off!

Gary Woodfine
Latest posts by Gary Woodfine (see all)