Structuring a Vue + Vuex project Structuring a Vue + Vuex project vue.js vue.js

Structuring a Vue + Vuex project


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.