Subscribe now

Vuex and Vue-router [08.15.2017]

Hello and welcome back to our tutorial series on building an app with Vue.js. Today we're going to be configuring our app using vuex and vue-router.

Getting Started

Before we begin, we need to open up the project in your favorite text editor then add the following files to src/components/.

Login.vue
Navbar.vue
Signup.vue
Taskbox.vue
Todo.vue

Inside of Login.vue, let's add the basic layout code.

<template lang="pug">

<template>

<script>

</script>

<style lang="stylus">

</style>

Now let's copy this code over to the other files inside components/.

Great, we will come back to these in a later lesson. However, you will see why we went ahead and created these Vue files soon enough.

Setting up main.js

Let's open main.js and make a few changes...

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import VueMaterial from 'vue-material'
import VueResource from 'vue-resource'
import 'vue-material/dist/vue-material.css'

Vue.use(VueMaterial)
Vue.use(VueResource)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  template: '<App/>',
  components: { App }
})

First, we are importing all of the modules our Vue app needs. Then, we are telling Vue to use the vue-material and vue-resource modules. Finally, we're bootstrapping the actual app and importing our router into the app along with telling it to use the App.vue component to act as the root component for our application.

Vuex

Now we need to setup Vuex. To do this, let's create Store.js in the src/ directory. Now let's insert some code...

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

let state = {
    username: '',
    id: '',
    // task = Object => {name: String, id: String}
    tasks: [],
    authenticated: false
  }

const mutations = {
  setProfile (state, profile) {
    state.username = profile.username
    state.id = profile.id
    profile.tasks.forEach(el => {
      state.tasks.push({name: el.name, id: el._id})
    })
  },
  addTask (state, task) {
    state.tasks.push({name: task.name, id: task.id})
  },
  removeTask (state, taskname) {
    state.tasks.forEach((el, index) => {
      if (el.name === taskname) {
        state.tasks.splice(index, 1)
      }
    })
  },
  editTask (state, task) {
    state.tasks.forEach((el, index) => {
      if (el.id === task.id) {
         state.tasks[index].name = task.newTaskName
      }
    })
  },
  logout (state) {
    state.username = ''
    state.id = ''
    state.tasks = [],
    state.authenticated = false
  },
  login (state) {
    state.authenticated = true
  }
}

const actions = {
  setProfile (context, profile) {
    context.commit('setProfile', profile)
  },
  addTask (context, task) {
    context.commit('addTask', task)
  },
  removeTask (context, taskname) {
    context.commit('removeTask', taskname)
  },
  editTask (context, task) {
    context.commit('editTask', task)
  },
  logout (context) {
    context.commit('logout')
  },
  login (context) {
    context.commit('login')
  }
}

export default new Vuex.Store({state, mutations, actions})

As you can see, we have imported Vue and Vuex then told Vue to use Vuex. Then we have defined state. This is going to be the central data model for the application. Then we have mutations. Here we have an object that is populated with functions that will carry out the mutations needed in the state section we just defined. Each function must have a state parameter that will access the data in the aforementioned state variable. The second parameter will be the value that is passed in to the function. Lastly, we have actions which will be dispatched from the Vue components themselves. All these do is receive a dispatch from the Vue component, then calls the previously mentioned mutation as defined from before. Then we export everything in a Vuex Store for use in the rest of the application.

Router

Now let's go to src/router/index.js and make some changes.

import Vue from 'vue'
import Vuex from 'vuex'
import Router from 'vue-router'
import Hello from '@/components/Hello'
import Login from '@/components/Login'
import SignUp from '@/components/Signup'
import Todo from '@/components/Todo'
import Store from '../Store'

Vue.use(Router)
Vue.use(Vuex)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'Todo',
      component: Todo,
      beforeEnter: (to, from, next) => {
        if (Store.state.authenticated) {
           next()
         } else {
           next('/login')
         }
      }
    },
    {
      path:'/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/signup',
      name: 'Signup',
      component: SignUp
    }
  ]
})

Conclusion

Here you can see we have imported Vue, Vuex, Vue-Router, and all of those Vue components we created earlier. Then told Vue to use vue-router and vuex. Lastly we are exporting our routes. Each having a defined path, name, and specific Vue component for each route. However, take note of the '/' route. Here we have beforeEnter which we use to control access via the authenticated variable we created in Store.js. If a user is authenticated, they are let in, otherwise they are redirected to the Login route.