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 4: VUEX first setup

Ivano Dalmasso
Mar 1 · 6 min read

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

In this lesson we are going to add vuex, a centralized data store. This will give us the possibility to get and put data from there from all over the application.

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

What is vuex?

Vuex is a state management library that centralizes some of the data of the application, so it can be accessed from any component.

This is really useful, because working only with props and events for passing data can be nice and easy for component-to-component transmission, but for any application with multiple layers of components this would become really complicated.

This complication can be solved using a centralized store, in this case, vuex.

In this lesson we are going to insert the posts list in this store, and we’ll see how to setup it in an easy and modular way.

The configuration of the vuex store is going to be in a dedicated “store” folder, that the vue cli has already added for you if you used vuex at the start of the project setup. If not,you can just install it with npm install and create the store folder.

Inside the folder there is an index.js file that contains the setup and configuration of the store. It should be something like this:

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

It instructs Vue on how to use vuex and then exports a new vuex store. It passes to the constructor a configuration object with the following parameters:

  1. state: the actual “data” inside of the vuex store (just imagine it as the “data” parameter of a component). The state is made reactive by vue, so each change to the data is also reflected to the components.
  2. mutations: a list of synchronous functions that have to be called to change some data in the state. Each of this functions get the actual vuex state and a payload (it can be a custom object). A mutation is actually called passing its name to the “commit” method of the store.
  3. actions: another list of functions. These have to actually call a mutation to change some data, but can be asynchronous. Actually, you should never call a mutation from a component, but always do it from actions, and call these last ones from the components.
    An action gets in input a context object that contains the same set of methods/data of the store instance as first parameter, and can also get a custom object as second parm. An action is actually called passing the name as parameter in the “dispatch” method of the store.
  4. getters: a list of functions that actually work as computed properties for a vuex store.
  5. modules: a list of vuex modules. In bigger application the store can become really huge, so it is better to split the data and the code for different application scopes in different application modules. In this application we are going to use them also if it is not mandatory. A module itself is actually only a normal exported vuex configuration object. All modules share the same name space, so, for example, if a module use a state variable with name “name”, another module cannot. To solve this problem the modules can be “namespaced”, this actually means that all the names will have a named namespace prefix.

Add modules to the application

export default {
namespaced: true,
state: {
posts: [
{
id: 1,
user: "idalmasso",
date: "2021-01-19 15:30:30",
post:
"Today I'm feeling sooooo well...",
comments: [
{
id: 3,
user: "Nostradamus",
date: "2021-01-20 20:30:34",
post: "LOL"
},
{
id: 4,
user: "FinnishMan",
date: "2021-01-20 20:30:34",
post: "Please..."
}
]
},
{
id: 2,
user: "cshannon",
date: "2021-01-19 15:25:20",
post: "Say something here"
}
]
},

mutations: {
ADD_POST(state, post) {
state.posts.push(post);
},
DELETE_POST(state, id) {
state.posts = state.posts.filter(post => post.id != id);
}
},
actions: {
async addPost(context, post) {
context.commit("ADD_POST", post);
},
async deletePost(context, id) {
context.commit("DELETE_POST", id);
}
},
getters: {
allPosts(state) {
return state.posts;
},
userPosts: state => user => {
return state.posts.filter(post => post.user === user);
}
}
};

Here we can see all the things we talked about before: the module is actually namespaced by the flag “namespaced”, there is a state containing the “posts” list, there are two mutations, ADD_POST and DELETE_POST that manipulate the state, the actions contains two async functions that commits the relative mutations, and finally there are two getters function to get all the posts and the list of the posts of a user.

This code is almost self-explanatory, so just add also the index.js in the UserStore folder like this:

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;
}
}
};

Here the state contains a user object, that contains the actual logged user, (that will be always the same, right by now… We’ll change that), and two mutations and actions to use for the login/logout functionality. Right by now, this only do the work in the vuex store, so it is not really useful, but this is almost only as a placeholder for future functionalities.

Now, to use the two modules we should only import and add them to the main index.js in the store folder in the right parameter:

import postsModule from "./postStore/index.js";
import usersModule from "./userStore/index.js";
...
modules: { posts: postsModule, users: usersModule }
...

Note that we have given the name “posts” to the postsModule and “users” to the usersModule. Because the two modules are namespaced, this name will be the prefix to use when referencing objects they contains.

Now last thing to do to see the actual posts in the components is to use them: just go in the Posts.vue component, and remove from the data configuration parameter the “posts” array and create a new computed method also named “posts” (so nothing else needs to be changed):

computed: {
posts() {
return this.$store.getters["posts/allPosts"];
}
}

So, here we can see that we can access the objects inside the store via the “$store” keyword in the vue instance. Note how the allPosts method name is prefixed with the module name.

Also, remove the posts list and the user in the User.vue component’s data parameter. Then, add the following two computed methods:

userPosts() {
return this.$store.getters["posts/userPosts"](this.user.username);
},
user() {
return this.$store.getters["users/currentUser"];
}

So, the userPosts get the parameter “this.user.username” that is gotten from the second computed method (remember that computed methods don’t have parenthesis when called).

Now, with this all set up, the posts and the users management is going to be centralized in the store (as well, in future, also for the authentication stuff). In next chapter we’re going to actually change a bit about this store and start make use of its functionality.

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/.