Setting up a Vuex Store with Nuxt
Tags: vue, javascript, vuex
Published: 2022-02-16 19:34:48

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](https://nuxtjs.org/docs/get-started/installation)

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

```javascript
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
    }
})
```

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:

```javascript
// 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
    }
}

```

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. 

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

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. 

```javascript
          <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>
```

on the Data

```javascript
  data() {
    return {
      selected: ''
    }
  },
```

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.

```javascript
  watch: {
    selected() {
      this.$store.commit('app/SET_SIGN', this.selected)
    }
  },
```

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.

```javascript
import { mapState } from 'vuex'

  computed: {
    ...mapState(
      'app',
      ['sign',
      'today']
    )
  },
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vvanbg66o8xdgcnvxyem.png)


We can display that if we want by: 

```javascript
<p>Your sign is: {{ this.sign }}</p>
```

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:

```javascript
  data() {
    return {
      selected: '',
      isReading: false
    }
  },
```

and we add the getToday method and the reset method:

```javascript
  methods: {
    getToday() {
      this.$store.dispatch('app/GET_TODAY')
      this.isReading = true
    },
    reset() {
      this.isReading = false
    }
  }
```

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

```javascript
        <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>
```

The result you can check out below:

[Check out Vue Astro sample deployed version](https://vue-astro.netlify.app/)

You land on the page

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvnfkyyqkr2cpd0s6vp3.png)


You select the sign and click

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lsbssbweagyl5tpnzh4x.png)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5blmcut3tnw1ibtql47n.png)


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


[Check out the Vuex docs](https://vuex.vuejs.org/guide/)  

[Check out the Flux docs](https://facebook.github.io/flux/)  
[Check out the Repo for Vue Astro](https://github.com/raulsposito/vue-astro)

[Read more: 4 ways to Setup Vuex](https://masteringnuxt.com/blog/four-ways-to-setup-vuex-in-nuxt)

Stay tuned for more state management tips on Vue!

[Pinia](https://pinia.vuejs.org/)