Logo credits to vuejs.org and golang.org

Social application with Vue.js and GO

Create and serve a twitter like application with vue.js and golang PART 5: VUEX finalization

Ivano Dalmasso
Mar 8 · 7 min read

This is the fifth part of this serie. Check here all the parts:

In this lesson we are going to update the vuex store, we will have a better logic to maintain the authentication of the user. Then we will update the application to use the vuex store we have created

Main target here is to update the frontend project, you can find the code here.

Improve the vuex store

So just create a folder “src/store/authStore” and move inside it the code bound to the authentication that was previously in the User store:

export default {
namespaced: true,
state: {
user: {
id: 1,
username: "idalmasso",
description: "Here is the description",
//here there will be the logic for auth and so on...
loggedIn: false
}
},
mutations: {
LOGIN(state) {
state.user.loggedIn = true;
},
LOGOUT(state) {
state.user.loggedIn = false;
}
},
actions: {
async login(context) {
context.commit("LOGIN");
},
async logout(context) {
context.commit("LOGOUT");
}
},
getters: {
currentUser(state) {
return state.user;
},
isLoggedIn(state) {
if (!state.user) return false;
return state.user.loggedIn;
}
}
};

Just a little refactoring in this, the code is the same as before. Now the Users store can also be changed like this:

export default {
namespaced: true,
state: {
loadedUsers: [
{
id: 1,
username: "idalmasso",
description: "Here is the description",
//here there will be the logic for auth and so on...
loggedIn: false
}
]
},
mutations: {
ADD_USER(state, user) {
if (state.loadedUsers.some(u => u.username == user.username)) {
state.loadedUsers.splice(
state.loadedUsers.indexOf(u => u.username == user.username),
1
);
}
state.loadedUsers.push(user);
}
},
actions: {},
getters: {
getUser: state => userid => {
if (state.loadedUsers.some(user => user.username == userid)) {
return state.loadedUsers.find(user => user.username == userid);
} else {
//Here I'll have to request from the server!!
return {};
}
}
}
};

where we have removed the authentication code, and just added the ADD_USER mutation, that will let us to add a user to the array in the state data, and added a getter “getUser”: this returns a function that from the userid returns the respective user from the store. We used the username as id for simplicity here, in a real application probably you would prefer to use an id of some sort.

Just note that in this application we are going to insert in the store all the users and all the posts from the database everytime. This is also only for simplicity, in real applications you would want to fetch from the server and maintain only some of the data (i.e. the most recent posts of people you follow, the last viewed users, etc.)

As last, remember to add the import module in the general index.js store file, in “src/store/index.js”.

Change the components to reflect the store changes

Now, in the User component, we can add the props configuration:

props: {
userid: { type: String, default: “” }
},

And then change the “user” computed method to return the user from the store like this:


return this.$store.getters[“users/getUser”](this.userid);

This will get the function “getUser” from the store getters and call it with parameter “this.userid”.

Now, we’d like to change the requests to this route to include this userid parameter.

The first place where we want to change this is in the applicatin bar. This is actually pretty straightforward: we have just to change in the data configuration option the link to the user view, and make it have a userid parameter. This is easily done by doing this:

links: [
...
{
name: "User",
to: {
name: "User",
params: {
userid: this.$store.getters["auth/currentUser"].username
}
}
}
]

This code gets the parameters data from the “currentuser” getter of the auth store, and use it for the routing to the User component. Pretty easy right?

Now it is possible to expand this thing a little, and make sure that all posts headers become links to the user who wrote the actual post. We do this in SinglePost component, as first simply add a “linkUser” method like this:

linkUser(username) {
return {
name: "User",
params: {
userid: username
}
};
}

This method builds the link object requested by the router, so it can navigate to the correct page using a username parameter. In this way we only have to make a little change to the title of the card in the template to get this working, changing the call to the header template of the post in this

<template v-slot:header>
<h3>
<router-link :to="linkUser(post.user)">
{{ postTitle(post)}}
</router-link>
</h3>
</template>

This will update the title of each post to be a link to the user page. It’s easy to update also the comment title in the same way, in the comment card:

<template v-slot:header>
<h3>
<router-link :to="linkUser(comment.user)">
{{ postTitle(comment)}}
</router-link>
</h3>
</template>

As you can see the code is almost the same, just because we kept the structure of comment and post objects really similar.

Now you can try to play with the store, add some user in the User store data object, some post of these users in the Posts store, and see that the links actually works correctly. Also, the link in the application bar will route you to the User page of the user in the auth store.

As last thing, let’s start to add a little functionality in the application bar to make use of the authentication store.

We added in the last lessons a “LOGIN” button, that didn’t do anything at all. Now add a couple of methods in the applicationbar component that manage to simulate a login/logout functions:

login() {
this.$store.dispatch("auth/login");
},
logout() {
this.$store.dispatch("auth/logout");
}

and a computed method that tells us if the current user is actually logged in:

loggedIn() {
return this.$store.getters["auth/isLoggedIn"];
}

We can use these to display and get the login/logout behaviour in the template, changing the LOGIN button we had previously to this:

<div class="right-links ">
<a class="app-bar-item" href="#" v-if="!loggedIn" @click.prevent="login">LOGIN</a>
<a class="app-bar-item" href="#" v-if="loggedIn" @click.prevent="logout">LOGOUT</a>
</div>

This template shows the LOGIN button if the loggedIn computed method is false, else shows the LOGOUT button. The @click is the normal v-on handler for events that we saw previously.

The .prevent prefix on the handler actually is a modifier that makes sure that if there is some “standard” behaviour that would be called, it is not, so if for example this button would be a submit button on a form, the click of the button wouldn’t trigger a get request and so also the refresh of the page from the server (in this actual case this .prevent is not needed).

So now when the LOGIN button is pressed, the authentication action is performed asynchronously and when the state actually change, the getter method, that is reactive, will change the value of the computed property, used for define the behaviour of the page, hide the LOGIN button and show the LOGOUT one.

We actually added a couple of methods, login and logout, and a computed property, isLoggedIn, that are exactly wrappers of actions and getters of the store. This is a common procedure, so vuex has some helpers function to make this easier, mapGetters and mapActions.

So we can make one last change, this does not change the behaviour of the application but only makes the code more clear and compact: just import the two functions before the export of the applicationBar component:

<script>
import { mapGetters } from "vuex";
import { mapActions } from "vuex";
export default {
...

Now use these helpers in the configuration options like this:

methods: {
...mapActions({
login: "auth/login",
logout: "auth/logout"
})
},
computed: {
...mapGetters({ loggedIn: "auth/isLoggedIn" })
}

So, the “auth/login” action is linked to the login method, the “auth/logout” to logout and the “auth/isLoggedIn” getter to the “loggedIn” computed property in a more readable way.

In this way we have a nice backbone to use for the next steps, in the next lesson we are going to finally create an input system to create posts and comments and push them into the store.

Nerd For Tech

From Confusion to Clarification

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.

Ivano Dalmasso

Written by

Always looking to learn new things, and loving see things work as I want

Nerd For Tech

NFT is an Educational Media House. Our mission is to bring the invaluable knowledge and experiences of experts from all over the world to the novice. To know more about us, visit https://www.nerdfortech.org/.