DEV Community

Cover image for Setting up a Vuex Store with Nuxt
Raul
Raul

Posted on

Setting up a Vuex Store with Nuxt

There's a lot to learn out there about Flux, Vuex, Nuxt, Vue, a framework of a framework, and so on. My idea here is to keep it as simple as possible. I really encourage you to go and read the docs for all that's out there so you can deep dive into them. The docs for all these libraries are super well written and easy going (in comparison to most software documentation).

So back to our project, I had the idea to build a Horoscope App, using Vue and Vuex for pretty much everything that contains state within the app. So I figured once the user claims their sign, we would make the API call and then get a prediction/reading for the user.

For this purpose I'm going to use this awesome API:

https://github.com/sameerkumar18/aztro

Ok, so let's start the project with:

yarn create nuxt-app <YOUR PROJECT NAME>

Check out Nuxt docs

Then, after the project's boilerplate is created, we jump into our store folder and add touch store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
// Here we import everything that is exported
// from the below directory, allowing us to create the store
import * as app from './modules/app/index'

Vue.use (Vuex)

export default () => new Vuex.Store({
    modules: {
        app
    }
})
Enter fullscreen mode Exit fullscreen mode

Then we create a new directory inside the store so we can give life to our app module inside of it:

mkdir store/modules

mkdir store/modules/app

touch store/modules/app/index.js

Inside the newly created index.js file, we add:

// We import axios since we'll need it
// to make the api calls later on.
import axios from 'axios'

// We make namespaced true so that we
// can call the modules like: app/mutations
export const namespaced = true

// We export all pieces of the store as constants
// that we will import on the index file we saw previously
export const state = {
    sign: null,
    today: []
}

export const mutations = {
    SET_TODAY(state, value) {
        state.today = value
    },
    SET_SIGN(state, value) {
        state.sign = value
    }
}

Enter fullscreen mode Exit fullscreen mode

Then for the most important part. We create the action that's going to fetch the given horoscope. We will send a post request to the endpoint, interpolating the user's selected sign we got from the store and making the api call. Then with the response we commit the mutation to have our horoscope reading saved in the store and accessible for all the app.

export const actions = {
    GET_TODAY({ commit }) {
        axios.post(`https://aztro.sameerkumar.website/?sign=${state.sign}&day=today`)
        .then(response => {
            commit('SET_TODAY', response.data)
        })
    }
}
Enter fullscreen mode Exit fullscreen mode

With that last piece added to the app module, we can go back to the template to handle how we are going to connect all the pieces to the user.

We will have to create a select menu, for the user to select their sign from.

          <select
            id="sign"
            v-model="selected"
            name="sign"
            class="mt-12 block w-full py-2 text-base border-gray-300 focus:outline-none focus:ring-purple-500 focus:border-purple-500 sm:text-sm rounded-md"
          >
            <option disabled value="">Please select your sign</option>
            <option>Aries</option>
            <option>Taurus</option>
            <option>Gemini</option>
            <option>Cancer</option>
            <option>Leo</option>
            <option>Virgo</option>
            <option>Libra</option>
            <option>Scorpio</option>
            <option>Sagittarius</option>
            <option>Capricorn</option>
            <option>Aquarius</option>
            <option>Pisces</option>
          </select>
Enter fullscreen mode Exit fullscreen mode

on the Data

  data() {
    return {
      selected: ''
    }
  },
Enter fullscreen mode Exit fullscreen mode

Using the v-model directive we connect the selected data to the user's selected value. That way we can watch that property and use it to connect it to the store.

  watch: {
    selected() {
      this.$store.commit('app/SET_SIGN', this.selected)
    }
  },
Enter fullscreen mode Exit fullscreen mode

We also need to use the helper mapState and the spread operator to connect the global store values to our component, making them available for our use.

import { mapState } from 'vuex'

  computed: {
    ...mapState(
      'app',
      ['sign',
      'today']
    )
  },
Enter fullscreen mode Exit fullscreen mode

So if we now go to the Vuex console on the browser we can see that the selection commits a mutation to the store, with the payload of the sign selected.

Image description

We can display that if we want by:

<p>Your sign is: {{ this.sign }}</p>
Enter fullscreen mode Exit fullscreen mode

We now need a button, to trigger the api call once the sign is selected and retrieve us with the horoscope we came looking for.
For that matter I also created a boolean value, that is going to create some conditional rendering on the UI and make the whole thing have some sense.

On the data we add isReading property:

  data() {
    return {
      selected: '',
      isReading: false
    }
  },
Enter fullscreen mode Exit fullscreen mode

and we add the getToday method and the reset method:

  methods: {
    getToday() {
      this.$store.dispatch('app/GET_TODAY')
      this.isReading = true
    },
    reset() {
      this.isReading = false
    }
  }
Enter fullscreen mode Exit fullscreen mode

Then under the select menu we add this to the template:

        <p v-if="!this.isReading" class="fadeIn pt-12 text-xl font-semibold text-white">Your sign is: {{ this.sign }}</p>

        <button
          type="button"
          v-if="!this.isReading"
          v-on:click="getToday"
          class="mt-12 inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
        >
           Get Today's Horoscope ☆
        </button>

        <div v-if="this.isReading" >
          <p class="fadeIn pt-12 text-xl font-semibold text-white">{{ this.sign }} Date Ranges: {{ this.today.date_range }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Date: {{ this.today.current_date }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Mood for {{ this.sign }}: {{ this.today.mood }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Color for {{ this.sign }}: {{ this.today.color }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Lucky Number for {{ this.sign }}: {{ this.today.lucky_number }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Lucky Time: {{ this.today.lucky_time }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Sign Compatibility: {{ this.today.compatibility }}</p>
          <p class="fadeIn pt-12 text-xl font-semibold text-white">Today's Reading for {{ this.sign }}: {{ this.today.description }}</p>
        </div>

        <button
          type="button"
          v-if="this.isReading"
          v-on:click="reset"
          class="mt-12 inline-flex items-center px-6 py-3 border border-transparent text-base font-medium rounded-md shadow-sm text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
        >
            Ask Another Sign  
        </button>
Enter fullscreen mode Exit fullscreen mode

The result you can check out below:

Check out Vue Astro sample deployed version

You land on the page

Image description

You select the sign and click

Image description

You can select another sign, that would loop without actually refreshing the page, it would just re render what's already there.

Then you can call the api again and get a new horoscope reading.

Image description

Hope you enjoyed the simple setup. Now it's time to make your next project more scalable!

Check out the Vuex docs

Check out the Flux docs

Check out the Repo for Vue Astro

Read more: 4 ways to Setup Vuex

Stay tuned for more state management tips on Vue!

Pinia

Top comments (0)