Photo by Yancy Min on Unsplash

How to structure app with vuex js and axios with modules

João Nascimento
10 min readAug 20, 2020

--

Vuex Application Structure guide

Note: pay attention to bold word.

Although, Vuex doesn’t restrict the structure of your code, there are a few ways to easy to improve the quality of your code, don’t lose yourself in the code.

The first principle is centralised in the store.

The only way to change the state is by confirming (or committing to) mutations, which are synchronous transactions.

Asynchronous logic must be encapsulated and can be composed with actions.

As long as you follow these rules, it’s up to you how to structure your project. If your store’s file is very large, just start dividing the actions, mutations and getters into separate files with modules.

Here is an example of a project structure:

First of all, you need to understand the State Management of Vuex.

Vuex are split in parts:

State — where the state of variables is store

View — view a declare state mapping, to access the state wit getters indirectly

Actions — to change a state

When you start to have several components that share a common state, quickly increase the complexity.

For example you have multiple views, each of view change the state of a variable, so if you have a count variable, one view add one, and other view decrease by one, this actions need to be updating the same state.

This look like simple, passing properties (props) to nested components, father and children components, but if the components aren’t father and child, they are sisters components, this mean the views appears at the same time, if you decrease one, they update the view of the other.

The solution is Vuex, Vuex extracts the shared state from the components and manages it in a global singleton.

Vuex helps share state management, but with a cost of more repetitive code. Even in simple project I use vuex because a simple project tends to become more complex in future developments.

How vuex work??

Look the following diagram, as a quote from Dan Abramov

“Flux libraries are like glasses: you’ll know when you need them.”

Now, if you start to make a big store file you will want to split to small files, perhaps split by models. You will need Modules.

What are Modules, and how they work??

However, as our app grows in scale, the store can get really bloated.

Vuex allows us to use modules. Each module can contain its own state, mutation, action, getters, and even other modules.

Actions, mutations and getters in modules are still registered under the global namespace, this allows multiple modules to react to the same type of action or mutation.

Example of store with modules.

As you can see it is easy to split and to understand the logic behind these modules.

When you call a mutation, if you have different names, it is important for non-collision, you call like these:

The vuex knows witch one is being called. And change the state of these.

If you have a getter in the view the vuex automatically will update these views.

When a component needs to make use of several store state properties, declaring this computed data can be repetitive and verbose.

To help us with this, we can use the mapState helper which generates computed getter functions for us, saving a few lines of code.

However, to use it with other local computed data, we would have to use a utility to merge several objects into one to pass the final object to the computed.

To simplify this, we use the Spread Operator, leaving our state mapping as follows: mapState

Note that, as a first parameter, we pass the module name, and then an array with the states that will be mapped to our component.

Remembering that, even though we are using Vuex, it does not mean that you should leave everything in Vuex state. This is important!!!

Although putting more state into Vuex makes your state mutations more explicit and debuggable.

How debug vuex, if you use google chrome, you will appreciate this extension .

For example, if a piece of state belongs strictly to a single component, it may be good to leave it only as a local state.

Let’s talk about Getters

Filtering with getter, for this you can use like the following:

Using this state, you can call the getter like these:

Filtering through a list of items and count them.

Now take a look to the main component

We mapped our getter in almost the same way we did as state, however, now using mapGetters and rendered it in our DOM.

And finally, our application shows the rendered result.

Mutations

Mutations is the only way you can call to change a state. Although, mutations seems very similar to actions: each mutation has a type string and a handler.

It is a standard commonly seen to use constants for mutation types in various implementations. This allows the code to take advantage of tools like linters.

We will build two mutations: one to increase our count state and another to decrease. Our mutation file inside the store / module-example directory will look like this:

Mutations can also receive an additional argument called payload. In most cases the payload is an object containing information (for example, an API response) to be passed on to the state.

Now, on our main component, we add two buttons and the mapMutation to change the count state.

Our application now has two buttons that change the state of our counter.

Application with increment and decrement counter

In Vuex, mutations are synchronous transactions.

And how should i handle with asynchronous operations??

The answer is with Actions.

Actions are similar to mutations. The differences are as instead of changing the state, actions confirm (or commit) mutations, you have to call actions, and the action call mutation.

Actions can contain arbitrary asynchronous operations.

Note that we simulate asynchronous operations in our actions by adding a small delay with setTimeout. We replaced the mutations in Index.vue with actions and modified our buttons to trigger them.

When clicking on the increment and decrement buttons, it takes a second for the count state to mutate.

But where is the global state management?

For now, we’ve only seen the change of state in a single view. However, let’s now do an example so that we can see more clearly how all this management is done separately from the local state of the Vue components.

First, let’s create a vue component, with two other increment and decrement buttons. In the components directory we create the CButtons.vue file.

In these components we will use the same increment and decrement logic that we did in Index.vue with the mapping of actions:

On the Index.vue page we import our component and register it:

The result now is our Index.vue page with four buttons, two of which are in the HTML of Index.vue itself, and the other two of the imported CButtons component.

Normally, in order to be able to exchange information between parent / child components, props and events were necessary. However, with Vuex we can access the store anywhere in our application.

Now the problem of axios (http responses) and store when you initialize a component

Following our example, if you need to store the increase and decrease of a state in a Database??

How should I do???

Generally our components receive Vuex states and actions via the vuex property in the component, like this:

Component.vue

This is the basic structure of how to obtain the properties stored in the store and their mutations (actions).

But… If you want to to have a component independent authentication service, that is, that it be contained within a file and that it queries the store directly without the need to encapsulate it within a component as in the code above.

If you search on the internet outside, you will see many examples like the code above, and in Vuex’s own documentation it looks like this. Another piece of common code that you find out there to initialize the store is something like this:

// store.js

// main.js

Well… I already had the store on my App.vue component and it was available for every application.

OK, but remember my authentication service (authService)?

So that’s when I decided to take a risk and import the store into a file called index.js inside a folder named authService and voilà !!!! Now it was enough for me to import authService that I had access to the content of the store. But wait! It wasn’t because of the folder and even less the names, I did it precisely to organize the code.

Now I can have the service as follows:

// main.js

//index.js em /vuex/auth

// store.js

And importing authService:

// index.js em /services/authService

When I need to use the authentication service to write the token from some component, I do it as follows: //MyComponent.vue

How to structure API calls in Vue.js?

I am currently working on a new Vue.js. It depends a lot on API calls to my back-end database.

For many things, I use Vuex stores because it manages data shared between my components. When looking at other Vue projects on github, I see a special vuex directory with files that handles all actions, states and so on. Therefore, when a component needs to call the API, it includes the action file from the vuex directory.

But, for messages, for example, I don’t want to use Vuex because this data is only important for a specific visualization. I want to use the component specific data here. But here’s my problem: I still need to consult my API. But I must not include the Vuex stock file. So, in this way, I must create a new stock file. That way, I have a specific file with API actions for vuex and unique components.

How should I structure this?

Creating a new ‘api’ directory that handles actions for vuex data and component-specific data?

Or separate it?

I’m using axios as an HTTP client to make API calls, I created a gateways folder in my src folder and placed files for each backend, creating axios instances, as followsmyApi.js

Now, in component, how we can get data?

Likewise, you can use this to get data for your vuex store as well.

If you are keeping product-related data in a dedicated vuex module, you can dispatch a method action on the component, which will call the back-end API internally and fill the data in the store, the code will look like the following:

Component.vue:

Vue Store code

I am mainly using the Vue Resource. I create the services directory and place all connections on the endpoints, for example, PostService.js

SomeView.vue

Calling API:

Getting all results

Please clap me, and see my others articles about vuex…

https://joonascimento-89605.medium.com/vue-router-tutorial-part-1-draft-f29b0cf15534?sk=07647f17675a592568a1607ed575e01e

--

--