Vuex for stage management Nativescript-vue

When starting this NativeScript-vue app I realized at some point I'm going to make calls to the API to fetch data and as well as interacting with it with some small actions. This app will allow captains to manage bookings (for the time being) which will mean that I need to to have the ability to:

  1. Fetch Bookings (Pending / Confirmed) - we decided that cancelled, declined, and completed bookings were irrelevant for the time being for this app.
  2. Fetch Events for the calendar - The events are Bookings (number 1), and blocked dates
  3. Confirm or decline a pending booking.
  4. Add / delete blocked dates (from the calendar). I could honestly do all of the API interactions inside the individual components, and store all the data in the local storage of the phone too, but I don't think that is ideal. I mean I'll be perfectly honest, some of the API calls are still left in the components and I have been contemplating taking them out and moving them into Vuex, but we'll see what time allows.

So what is Vuex? Well Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.. Being that some of the components will share data it makes more sense to store this data in a centralized store vs fetching when a component loads and or storing the data in the phones local storage. Also one quick side note my last relied on Vuex for everything (which I think is / was wonderful) however talking to a few ex employees I am not sure we were using proper naming conventions / yada yada yada, so I might be a tad off on a few things. That being said if / when you use Vuex, read the docs they are pretty straight forward and there are numerous resources available on the interweb. Easiest way to install Vuex is to npm i vuex. I like to create a store folder in the app root and then inside the folder create an index.js. Once we have this we now need to initialize / start up Vuex so we can use it throughout the app. This is done in the app.js (main.js in others and .ts in the typescript apps), but in here we need to import it / use it / add it to the rendering of the app:

import Vuex from 'vuex';
Vue.use(Vuex)
new Vue({
  render: h => h(App),
  store
}).$start()

And now we have Vuex installed and it is setup so we can start creating our Store!!!!!!!!!!!

For me Vuex consists of:
State - which is the source of truth for the application.

state: {
    user: {
      first_name: '',
      last_name: '',
      email: '',
      phone_number: '',
      mobile_phone_number: '',
      charters: [],
    },
    token: '',
    bookings: [],
    calendarEvents: [],
    loading: true,
    selectedCharter: '',
},

you want to initialize all properties that you will be using and mine grew as I build this app.

Mutations - The only way to change state in a Vuex store is by committing a mutation, and each mutation receives state as the first argument.

mutations: {
    setUser(state, payload) {
      state.user = payload;
    },
    setBookings(state, payload) {
      state.bookings = payload;
    },
    setCalendarEvents(state, payload) {
      state.calendarEvents = payload;
    },
    setSelectedCharter(state, payload) {
      state.selectedCharter = payload;
    },
    setLoading(state, payload) {
      state.loading = payload;
    },
    setToken(state, payload) {
      state.token = payload;
    }
  },

I like to use set as the prefix to my methods cause well it makes sense to me.

Actions - similar to mutations excepts actions commit mutations and actions can contain asynchronous operations (this is where I'll be fetching data from the API). Actions handlers receive the context objects which exposes the same set of methods/properties on the store instance so you can call context.commit, context.state, context.getters, and so on so forth. It exposes the entire API to the programmer.

actions: {
    setToken(context, payload) {
        //fetch Token (check creds of LOGIN)
    },
    setUser(context, payload) {
       //grab the user from the API with a valid token
    },
    setBookings(context, payload) {
      //fetch bookings from the API
    },
    setCalendarEvents(context, payload) {
      //fetch calendar events from the API
    },
    resetUser(context, payload) {
      let user = {
        first_name: '',
        last_name: '',
        email: '',
        phone_number: '',
        mobile_phone_number: '',
        charters: [],
      };
      context.commit('setUser', user);
    },
    setSelectedCharter(context, payload) {
      context.commit('setSelectedCharter', payload);
    },
    setLoading(context, payload) {
      context.commit('setLoading', payload);
    }
},

and yes some of the method names are the same as mutations but it all makes sense to me since when you call the store you specifically call commit/getters/dispatch/ you'll see.

Getters - These are basically computed properties for stores and they receive stat as their first argument. Basically a getters result is cached and will only re-evaluate if the dependency is changed. Super powerful and well above my knowledge. If you wanna take a deep dive into it more power to you.

getters: {
    getToken(state) {
      return state.token;
    },
    getUser(state) {
      return state.user;
    },
    getBookings(state) {
      return state.bookings;
    },
    getCalendarEvents(state) {
      return state.calendarEvents;
    },
    getLoading(state) {
      return state.loading;
    },
    getSelectedCharter(state) {
      return state.selectedCharter;
    }
  }

There are also modules and other things you can use but for me they were unnecessary.

So now that we have our store setup how do we actually "use" it to manage our state / data? Here is an easy one. So as you can see I have a loading property on state, that when the app is loaded it is initialized as true. When my App.vue is mounted I do a few things and here they are, and I'll go through them afterwards:

mounted() {
      if(ApplicationSettings.hasKey('token')) {
        this.$store.commit('setToken', ApplicationSettings.getString('token'));
      }
      this.$store.dispatch('setUser', this.$store.getters.getToken);
      this.$store.dispatch('setBookings', this.$store.getters.getToken);
      if(this.$store.getters.getSelectedCharter) {
        this.$store.dispatch('setCalendarEvents', {token: this.$store.getters.getToken});
      }
    },

Because Vuex is initialized in our app.js file we can use it globally by this.$store. commit = an action while dispatch = mutation. getters is pretty self explanatory, and you can always use this.$store.state, but again the getters are basically computed properties and will update whenever state is updated (action) so I never use it and don't really see a need too.

I don't know if that was super in depth or not but honestly it is very easy to use. Just understanding when to use an action vs mutation and understanding why getters are so useful. But this should 100% get you started and allow you to pass / save data throughout your nativescript application, or web app / PWA or in any instance where you use Vue and have to manage data throughout the application. I mean in the end if you truly wanted to you could 100% make an API call when a new component is mounted and you will never need this and you could just pass data between props and whatnot but man that just even for me seems like possibly the most inefficient / offshore way possible ( I only say offshore because I've taken over a project where they legit did that and I had to dip out cause I was like no thanks. There are some really great offshore devs too ).

54