Setting up a Vuex Store with Nuxt
Raul
Posted on February 16, 2022
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>
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
}
})
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
}
}
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)
})
}
}
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>
on the Data
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.
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.
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.
We can display that if we want by:
<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:
data() {
return {
selected: '',
isReading: false
}
},
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
}
}
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>
The result you can check out below:
Check out Vue Astro sample deployed version
You land on the page
You select the sign and click
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.
Hope you enjoyed the simple setup. Now it's time to make your next project more scalable!
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!
Posted on February 16, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.