Blog

How to Use Vuex

Category
Software development
How to Use Vuex

What is Vuex and how to use it?

Enterprise applications are complex because multiple parts of the state are used in many different components. State management libraries are often used for interactions between individual components.

Vuex state management pattern and the library are available for the Vue.js framework. It emerged similar to the Redux state management library. Like in Redux, Vuex is the “single source of truth” principle that is present – one app, one store. However, Vuex also does not have a dispatcher, unlike Flux or NgRX.

What is state management?

State management is a solution that is using events in order for different parts of the application to be aware of a change. There is a different approach also, where it’s possible to take a state in DOM or even a global object of the application. Store pattern is usually used where all mutable actions change the structure of the state. This type of state management facilitates a way of when and how a particular mutation can be triggered.

About Vuex best practices

Vuex should strictly be used for the following things:

  • When multiple parts of the application are expected to detect or change state 
  • When there is a need to share data between multiple components
  • When there is a complex interaction with the backend, for example multiple API calls
  • When an application interacts with a traditional REST API call or GraphQL

The basic things that Vuex contains are:

  • actions
  • mutations
  • state
  • getters
how to use vuex

Let’s start with a simple application

We’ll develop a simple application that will allow users to monitor the weather forecast in seven Croatian cities. The weather data will be taken from free open OpenWeather API service (https://openweathermap.org/).

First, we’ll generate a project:
vue create vuex-open-weather

Then we’ll install Vuex in a project:
npm install –save vuex@next

After that, we need to install axios library:
npm install –save axios vue-axios

It is necessary to create a store folder that will contain two files:

  • store.js
  • service.js

Within the store.js, it’s necessary to initialize the Vuex store. Also, we need to define empty objects for the following arguments:

  • state 
  • getters 
  • actions
  • mutations

Creating a store

import { createStore } from "vuex";
 
const state = {};
 
const getters = {};
 
const actions = {};
 
const mutations = {};
 
const store = createStore({
 state,
 mutations,
 actions,
 getters,
});
export default store;Code language: JavaScript (javascript)

Then, you need to initialize the store within main.js

import { createApp } from "vue";
import store from "./store/store";
import App from "./App.vue";
import router from "./router";
 
const app = createApp(App);
 
app.use(store).use(router);
app.mount("#app");Code language: JavaScript (javascript)

After it’s initialized, we’ll add two properties within the state object.

State

A state is an object that contains the state of the data at the level of the entire application. In practice, the data we store in the state must correspond to the data in the component. All business logic must be done before saving data to the state. 

Our state will contain:

  • citiesWeather in which we’ll store the current forecast for specific cities
  • cityWeather where we’ll store a forecast for the next period for the selected city.
const state = {
 citiesWeather: {},
 cityWeather: {},
}Code language: JavaScript (javascript)


Define the actions

Before displaying data, it’s necessary to define the actions that will be called, together with service from which individual data will be called. In addition to actions, it’s also necessary to define mutations that will change the state. Each mutation is defined by type and a handler. Through the mutation, it’s possible to send a certain payload, which will eventually manipulate the data within the state.

The application contains two actions that refer to the service of the same name through which we retrieve data. Instead of directly manipulating data from a particular action, we commit individual mutations. With all that said it is a good practice that we can adjust the data in the way, we need it.

const actions = {
 async fetchWeatherForCities({ commit }) {
   const response = await service.fetchWeatherForCities();
   commit("addWeatherForCities", response);
 },
 async fetchWeatherForCity({ commit }, { cityId }) {
   const response = await service.fetchWeatherForCity(cityId);
   commit("addWeatherForCity", response);
 },
};Code language: JavaScript (javascript)
export async function fetchWeatherForCities() {
 try {
   const response = await axios.get(
     `${process.env.VUE_APP_URL}/group?id=${zagrebId},${osijekId},${rijekaId},${splitId},${dubrovnikId},${zadarId},${varazdinId}&appid=${process.env.VUE_APP_API_KEY}&units=metric`
   );
   return response.data;
 } catch (e) {
   console.error("Failed to fetch weather for cities", e);
 }
}
 
export async function fetchWeatherForCity(cityId) {
 try {
   const response = await axios.get(
     `${process.env.VUE_APP_URL}/forecast?id=${cityId}&appid=${process.env.VUE_APP_API_KEY}&units=metric`
   );
   return response.data;
 } catch (e) {
   console.error("Failed to fetch weather city", e);
 }
}

Code language: JavaScript (javascript)
 
const mutations = {
 addWeatherForCities: (state, weather) => {
   state.citiesWeather = weather;
 },
 addWeatherForCity: (state, weather) => {
   state.cityWeather = weather;
 },
};Code language: JavaScript (javascript)

After the data has been successfully saved to the state, it’s necessary to define getters. Getters are used exclusively for communication between the state and the component.

const getters = {
 citiesWeather: (state) => {
   return state.citiesWeather.list;
 },
 cityWeather: (state) => {
   return state.cityWeather;
 },
};Code language: JavaScript (javascript)

If multiple components use the same getter, it’s best to define a global getter that will reduce boilerplate code. We can use an argument inside of the component to retrieve data of a certain getter. 

computed: {
   citiesWeather() {
     return this.$store.getters.citiesWeather;
   },
 },Code language: JavaScript (javascript)

Once the data is available for displaying inside of the component, we do a classic data binding between template and arguments or methods inside the component. Changing the data within the component as little as possible is recommended because as mentioned, the best practice is to change the data store in the mutation so that the state is the single source of truth.

Conclusion

The big advantage of Vuex is that there are no restrictions on how we structure the code. The most important thing, more precisely, the principle to adhere to is that everything is centralized within the store. We manipulate the data only during mutation. Having a global state management like Vuex is a benefit, especially when you develop a big application. The main benefits of developing and maintaining your application are much easier.

The whole code is available on my github repo – https://github.com/marmijic/vuex-open-weather

CONTACT US

Exceptional ideas need experienced partners.