Integration of Vuex into Nuxt Js - multiple ways

Integration of Vuex into Nuxt Js - multiple ways

Managing store data in Nuxt JS applications using Vuex

ยท

6 min read

What is NUXT JS ?

Nuxt JS is a front-end framework built on top of Vue JS which simplifies a lot of things for you out of the box like routing, importing components, adding plugins and more stuff.

Among the many advantages it offers to seasonal Vue JS developers, what probably stands out the most is the ability to pre-render Javascript on the server and then ship the files to the client. This is called server-side rendering of single-page applications (SPA). This trend is gaining more and more popular among developers for the few features it has to offer like faster loading time, search engine indexing, evaluating user data metrics on the server and more.

Background

I was curious to explore Nuxt JS for its possible use in my next project. I went through the official docs and learned the basics and slightly advanced concepts like store management using Vuex which would be the crux of this post. Let's start our project using create-next-app, and name this project 'nuxt-demo'.

npm init nuxt-app nuxt-demo

While creating the project you'd go through a series of questions where you'd be asked to pick front-end UI framework, choose Javascript or Typescript, pick a test framework and more options. Open this folder in your favorite text editor, I'd be using VS Code for this demo. I had issues with Node versions 17 and 18, so I'm using Node 16 and npm 8.19 for this. You can have nvm (Node version manager) in your system and can have multiple node versions installed.

Store Management using Vuex

What's cool is, store management comes configured by default with Nuxt JS. There is a folder directory structure and some naming conventions to follow to equip your project with state management. But, before we get there I'd like to configure axios in our project. Axios would be used to make API calls to the server, fetch the data and populate the store with the fetched data. Install axios through npm and configure it to be used inside the nuxt.config.js file.

publicRuntimeConfig: {
    axios: {
        baseURL: 'https://api.nuxtjs.dev',
    },
    myPublicVariable: process.env.PUBLIC_VARIABLE,
},

modules: ['@nuxtjs/axios'],

We have added Axios to the modules array. We've also used a base URL for all the axios calls, we've also setup env variables to be used in our project since the API you might be dealing with might have access credentials to be used. You can create the .env file on the root level of the project and have this variable called 'PUBLIC_VARIABLE'. You should be able to use this variable throughout your project. This is how your env file should look with some variables.

PUBLIC_VARIABLE="https://my-cool-website.com"
API_KEY="1234qwerapikey"

Right now by default, we only have one page in our Nuxt app which is the homepage of course. Let's create 'about.vue' file inside the pages folder, you don't have to manually add it to routing. It would be available by default on url '/about'.

<template>
  <div>
    <t-button variant="error">
      Submit
    </t-button>
    <p v-if="apiData">
      {{ apiData }}
    </p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      apiData: [],
    };
  },
  mounted() {
    this.callApi()
  },
  methods: {
    async callApi() {
      const mountains = await this.$axios.$get(`/mountains`);
      this.apiData = mountains;
    },
  },
};
</script>

In this component, I've included a sample API call which is made inside the mounted life-cycle hook. Later, in the same component, we would store this API data in our Vuex store variables. So, let's create our store then.

As the blog title suggests, we have multiple ways we can configure Vuex to be used inside Nuxt JS projects. But, I'd start with modules-based architecture which might be overkill for small projects but is a robust way of organizing store variables for large projects. Inside the store folder, we'd have a folder for all the modules identified in our project. For instance, if we're working on a blog app, then 'auth' can be a module, 'blog' can again be a separate module and so on. Here, I'd only add a sample module called 'cart'. Inside the store folder, create this folder named cart and have four files to handle state, actions, getters and mutations.

export default {
  getApiDataAction({ state, commit }, payload) {
    commit("setApiData", payload);
  },
};

getters.js

// /store/getters.js
export default {
  myGetter(state) {
    return state.apiData;
  },
};

mutations.js

// /store/mutations.js
export default {
  setApiData(state, val) {
    state.apiData = val;
  },
};

state.js

export default () => ({
  apiData: []
})

Now, we can modify our 'about.vue' page to have these state variables and actions included which would populate and display data from the API call.

<template>
  <div>
    <p v-if="apiData">
      {{ apiData }}
    </p>
  </div>
</template>

<script>

export default {
  computed: {
    apiData() {
      return this.$store.state.cart.apiData;
    },
  },
  mounted() {
    this.callApi()
  },
  methods: {
    async callApi() {
      const mountains = await this.$axios.$get(`/mountains`);
      this.$store.dispatch("cart/getApiDataAction", mountains);
    },
  },
};
</script>

I've included actions and getters from vuex store. I could have used mapActions and mapGetters from vuex, but for this example, I decided not to and instead access store variables directly using app context ($store). This brings me to the end of the first method of how we can integrate Vuex in Nuxt JS. This is scalable and maintainable for huge apps, hence my preferred way of organization. But, we'd take other ways of folder re-structuring as well that might suit more for smaller apps.

Another Method

This method is what I call a single file at root level inside the store folder for each component that forms Vuex store. Vuex store comprises of state, actions, getters and setters. To convert our previous architecture into this architecture we simply move the contents of 'cart' folder one level above to the root level inside the 'store' folder and that is it. We'd need to slightly modify the way we've called actions and getters inside 'about.vue' page.

this.$store.dispatch("getApiDataAction", mountains);
apiData() {
  return this.$store.state.apiData;
},

These are the changes I made as per the second architecture, we simply omitted 'cart' from our actions and getters if you compare it with the previous version.

All-in-one file method

Another architecture we can adapt to is to have all actions, getters, and setters for all modules in a single file called 'index.js' inside the store folder. The contents of the index file are captured below.

// state
export default () => ({
  apiData: []
})
// action
export default {
  getApiDataAction({ state, commit }, payload) {
    commit("setApiData", payload);
  },
};
// getter
export default {
  myGetter(state) {
    return state.apiData;
  },
};
// mutation
export default {
  setApiData(state, val) {
    state.apiData = val;
  },
};

This should work fine, you don't need to make any changes in the way you called actions and getters from the previous method.

Conclusion

This brings me to the end of this post. I discussed various ways of having Vuex store integrated into your Nuxt JS app. If you have anything to share, please leave it in the comments section. Thanks for the read! ๐Ÿ˜ƒ

ย