Introduction to vuex(part 2)

Eze Henry
5 min readJun 24, 2020

--

In part 1 of our tutorial, we were able to:

  1. set up our project
  2. Set up firebase
  3. Create our views(pages)
  4. Set up our routes

With that done, We would be working on our components and vuex in this part of the tutorial

Setting up vuex

By default, vuex has been set up by the vue CLI. You can find everything in a folder named store in the src folder

Vuex regular structure.

However, this folder structure might become difficult to handle when writing larger applications, But I won't be talking on the recommended structure in this tutorial, However, I have written on it previously so you can know more about it here. Moving on….

The index.js file of the store folder would initially look like this

import Vue from "vue";import Vuex from "vuex";Vue.use(Vuex);export default new Vuex.Store({state: {},getters: {},mutations: {},actions: {},modules: {}});

If you noticed, there are 5 objects in the store,

  1. State: The state is where all data is stored, also known as “the single source of truth”. In this application, the state would be used to store data e.g user details, books, e.t.c.
  2. Getters: Getters are like the computed property of a vue.js component, it is used for filtering or sorting data. e.g to get all active users
  3. Actions: Actions are used for asynchronous operations, basically actions are functions where you can fetch from an API, post to an API, perform complex logical operations e.t.c. Actions can be accessed by dispatching or mapping them. e.g
this.$store.dispatch('action',param)

4. Mutations: Mutations are used for synchronous operations and is mostly used to mutate state, It has many similarities with the actions the only difference is that actions are asynchronous while mutations are not. Mutations can be accessed by committing or mapping them. e.g

this.$store.commit("mutation", param)
  1. Modules: Modules are used for breaking the store into modules or compartments. I wouldn't be talking on this today, but I have written on this previously here

Now moving on to development, we would be writing code from here on. First, we would create our registration component’s template:

<template><div><form @submit.prevent="submitForm"> // .prevent is an event modifier 
//it performs the same thing as .preventDefault() which stops a page from loading when submitting a form.
<input type="email" v-model="email" placeholder="email"><input type="text" v-model="name" placeholder="name"><input type="password" v-model="password" placeholder="password"><button>Register </button></form></div></template>

Now to the script part of our registration component

<script>import {mapMutations} from 'vuex'export default {data: () => {return {email: null,name: null,password: null}},methods: {...mapMutations(['setUserInfo']), //mapping mutations to be able to //access itsubmitForm() {this.$firebase.auth.createUserWithEmailAndPassword(this.email, this.password).then(result => {let data = {name: this.name,email: this.email,id: result.user.uid,createdAt: Date.now()};this.$firebase.db.ref("users").child(result.user.uid).set(data).then(() => {this.setUserInfo(data); // accessing the mutation
//this is one way to access the mutation by mapping it. another way //is - this.$store.commit('setUserInfo', data)
this.$router.push("/borrowbooks");});}).catch(err => {
let message = Object.values(err)[0];
alert(message);});}}}</script>

We are able to access the firebase class in various components because we made it accessible in the entry point of our application in part 1. Now let's look at our setUserInfo mutation:

import Vue from "vue";import Vuex from "vuex";Vue.use(Vuex);export default new Vuex.Store({state: {user: null},mutations: {setUserInfo(state, userInfo) {state.user = userInfo; // a mutation is used to mutate state}},actions: {},modules: {}});

Now moving on to the add books component:

<template><div><input type="file" @change="uploadFile" class="file"></div></template><script>import {mapActions} from 'vuex'export default {methods: {...mapActions(['getFile']), // a mapped actionuploadFile() {const fileInput = document.querySelector(".file");const file = fileInput.files[0];this.$firebase.storage.child('library book').put(file).then(() => {
this.getFile(this); //how to access an action
}).catch(err => {console.log(err)})}}}</script>

In the template, we added input to take the file from a directory, then in the script we imported mapActions.

Note: mapActions and mapMutations are destructured in the methods property while mapState and mapGetters are destructured in the computed property.

With the code above we could upload a file to the firebase storage bucket. Now let's look at the action we mapped

import Vue from "vue";import Vuex from "vuex";Vue.use(Vuex);export default new Vuex.Store({state: {user: null,
doc: []
},mutations: {setUserInfo(state, userInfo) {state.user = userInfo;},
setDoc(state, doc) {
state.docs.push(doc)
},actions: {getFile({commit}, vueApp) {vueApp.$firebase.storage
.child('library book')
.getDownloadURL()
.then(link => {
commit('setDoc', link)
}).catch(err => console.log(err));}},modules: {}});

The aim of the action we mapped was to get the URL of the document we uploaded. If you noticed we committed instead of assigning to state, It is possible to do that but it is recommended that only mutations should be able to mutate the state. With this done, let's move to the borrowing component

<template><div><button v-for="(path, index) in doc" :key="index" @click="borrowDoc(path.link)">Borrow Document</button></div></template><script>import {mapState} from 'vuex'export default {computed: {...mapState(['doc', 'user']) //mapped user and doc so it could me //accessible in this component},methods: {borrowDoc(link) {let data = {name: this.user.name, // mapping state makes this accessibledoc: link}this.$firebase.db.ref("borrowers").set(data)}}}</script>

In this component you would see that we mapped doc and user which are objects in the state, mapping makes it accessible in the component.

Now let’s move to the part where we can see people who borrowed books

<template><div><div v-for='(person, index) in fetchBorrowers' :key="index">{{person.name}}</div></div></template><script>import {mapGetters} from 'vuex'export default {computed: {...mapGetters(['fetchBorrowers']) //a mapped getter},mounted() {this.$store.dispatch('getBorrowers', this) //another way to access an action}}</script>

Now let's move to the store to see the getter and the action we declared

import Vue from "vue";import Vuex from "vuex";Vue.use(Vuex);export default new Vuex.Store({state: {user: null,doc: [],borrowers: []},getters: {fetchBorrowers: state => {return state.borrowers.filter(x => x.name !== null)}},mutations: {setUserInfo(state, userInfo) {state.user = userInfo;},setDoc(state, doc) {state.docs.push(doc)},setBorrowers(state, people) {state.borrowers.push(people)}},actions: {getFile({commit}, vueApp) {vueApp.$firebase.storage.child('library book').getDownloadURL().then(link => {commit('setDoc', link)}).catch(err => console.log(err));},getBorrowers({commit}, vueApp) {vueApp.$firebase.db.ref("borrowers").once("value").then(result => {commit("setBorrowers", { ...result.val(), id: result.key });}).catch(err => console.log(err))}},modules: {}});

Like I defined getters previously they are used for filtering, so in this case, we are filtering borrowers who do not have their name set to null.

Well don't mind the stern face 😅.. Send me a note for clarifications.

Thank you for your time 😉.

--

--

Eze Henry

I write about things I wish I knew previously. Mostly on technologies like Javascript, Vue.js, python, Node. https://godofjs.me/