15

I am kind of confused here on where to place my global functions. In a lot of examples a main.js file points to an app component and this is placed somewhere within the html. This workflow would be fine for me If I were to simply contain all my logic within this app component. But I am combining components with Laravel functionality so this does not work for me.

Currently my main.js file contains a bunch of methods that I need to have access from anywhere in my app. These methods don't contain any broadcasting events so they can effectively be placed anywhere as long as they get a vue-resource instance.

My main.js file:

https://github.com/stephan-v/BeerQuest/blob/develop/resources/assets/js/main.js

Hopefully somebody can tell me where I could place my friendship methods if I were to use vuex or in general since this does not seem like best practice at all.

Thank you.

Stephan-v
  • 19,255
  • 31
  • 115
  • 201
  • Please add at least some bullet points with generic, abstract names of the functions in that linked main.js (since the link is broken). Also, it's not clear to me whether you refer to global functions/helpers for Vue.js or for the store (vuex) or both (according to your last paragraph it's only vuex). Please clarify. (Think about removing redundant tags) – try-catch-finally Jan 03 '19 at 15:02

1 Answers1

26

Vuex manages all of the data in your application. It's a "single source of truth" for data on your front-end. Therefore, anything that changes the state of your application, such as adding a friend, or denying a friend, needs to flow through Vuex. This happens through three main function types, getters, actions, and mutations.

Check out: https://github.com/vuejs/vuex/tree/master/examples/shopping-cart/vuex

Getters are used to fetch data from storage in Vuex. They are reactive to changes, meaning if Vuex data changes, the information in your component is updated as well. You can put these in something like getters.js so that you can import them in any module you need them in.

Actions are functions that you call directly, ie. acceptFriendRequest when a user clicks the button. They interact with your database, and then dispatch mutations. In this app, all of the actions are in actions.js.

So you'd call this.acceptFriendRequest(recipient) in your component. This would tell your database to update the friend status, then you get a confirmation back that this happened. That's when you dispatch a mutation that updates the current users' list of friends within Vuex.

A mutation updates the data in Vuex to reflect the new state. When this happens, any data you are retrieving in a getter is updated as well. Here is an example of the entire flow:

import {addFriend} from './actions.js';
import {friends} from './getters.js';
new Vue({
  vuex:{
    getters:{
      friends
    }
  },
  methods:{
    addFriend
  }
}

store.js:

export default {
  state:{
    friends: []
  },
  mutations:{
    ADD_FRIEND(state, friend) {
      state.friends.push(friend);
    }
  }
}

actions.js:

export default {
  addFriend(friend){
    Vue.http.post('/users/1/friends',friend)
      .then((response)=>{
        dispatch("ADD_FRIEND", response) //response is the new friend
      })
  }
}

getters.js

export default {
  friends(state) {
    return state.friends;
  }
}

So all of these are organized into their own files, and you can import them in any component you need. You can call this.addFriend(friend) from any component, and then your getter which is accessed from this.friends will automatically update with the new friend when the mutation happens. You can always use the same data in any view in your app and know that it is current with your database.

Some misc stuff:

  • getters automatically receive state as a variable, so you can always reference the state of your Vuex store
  • mutations should never be asynchronous. Do fetching/updating in actions and then dispatch mutations just to update your data
  • creating services (or resources) using Vue Resource will make fetching/updating/deleting resources even easier. you can put these in separate files and import them in your actions.js to keep the database retrieval logic separated. Then you'd be writing something like FriendService.get({id: 1}) instead of Vue.http.get('/users/1'). see https://github.com/vuejs/vue-resource/blob/master/docs/resource.md
  • Vuex works with vue devtools for "time-traveling". You can see a list of every mutation that has taken place and rewind them/redo them. It's great for debugging and seeing where data is being changed.
Jeff
  • 24,623
  • 4
  • 69
  • 78
  • 1
    Thanks for the lengthy explanation and helping me out here, means a lot to me. Just a question though; my friendship API call methods in this case do not actually have to update the vuex store. These calls simply make a standalone request to an api endpoint. Other parts of my app will be using vuex though. Is it still advisible to do it like your suggested when these methods do not actually need to update the store? – Stephan-v Jun 28 '16 at 11:51
  • 4
    If there is any other view in your application that would want to know the list of friends, then using Vuex would be the way to go. Then you don't have to re-fetch your list of friends in different places, and you always know you're sync'd with the database. But if it's more than you need then involving Vuex would just be extra work. In that case I would just create something like `/services/Friends.js` which has all of the functions for managing friendships, so you can import that anywhere you need it. – Jeff Jun 28 '16 at 11:55
  • If you separate it (vuex and local component data), where should you store the database logic to get data from the API? Not in the Vuex directory I think? In a separate directory named api? – Jordy Nov 26 '16 at 15:07
  • Should I only use the /services/ directory for scripts for components that doesn't use Vuex? Or should I use this directory for all components as a global actions directory? And, if needed, update Vuex from that script? – Jordy Nov 27 '16 at 00:58