Introduction
Architecture might not matter at the start of a project, but the ease at which components can be added or removed without breaking stuff shows how well the codebase was structured. Let's look at ways to make our Vue JS code better.
Use State, Map Getters and Actions.
Using state and the maps (i.e mapGetters, mapActions, mapState, etc) provided by Vuex makes code very reusable. Hard coding state to the data() object in your SFC because its "faster" will raise difficulties if some of those values are needed in the future.
<!-- first.vue -->
<template>
<h3>{{firstname}}{{lastname}}</h3>
</template>
<script>
export default {
data() {
return {
firstname: "",
lastname: ""
};
},
methods: {
async getFullName() {
const { firstname, lastname } = await fetchNameFromApi();
this.firstname = firstname;
this.lastname = lastname;
}
},
created() {
this.getFullName();
}
};
</script>
Project Manager: We need the firstname and lastname to show up on two more pages.
With that request, you'll keep copying, pasting, importing and exporting from different files.
Better Still,
const state = {
firstname: "",
lastname: ""
};
const actions = {
async getFullName({ commit, dispatch }, data) {
getFullNameFromApi().then(res => {
commit(mutate.FULL_NAME, res.body);
});
}
};
const mutations = {
//Set default mutation types in another file
[mutate.UPDATE_FULL_NAME](state, data) {
state.firstname = data.firstName;
state.lastname = data.lastName;
}
};
const getters = {
firstName: state => state.firstname,
lastName: state => state.lastname
};
const FullName = {
state,
actions,
mutations,
getters
};
export default FullName;
Then on our first.vue component,
<template>
<h3>{{firstName}}{{lastName}}</h3>
</template>
<script>
import {mapGetters, mapActions} from 'vuex';
export default {
methods:{
...mapActions(['getFullName']);
},
created(){
this.getFullName();
},
computed:{
...mapGetters(['firstName', 'lastName']);
}
}
</script>
Now, if we need to include a new component that needs the first and last names of our user, we can easily map the getters and the actions.
This also helps us avoid things like:
const firstname = this.$store.state.fullName.firstName;
const lastname = this.$store.state.fullName.lastName;
We can simply use getters
computed:{
...mapGetters(['firstName','lastName'])
}
Finally, this helps us abstract business logic from the SFC and makes testing easier. Allow the Store to handle all the logic, and the SFC should just handle stuff tightly coupled to it, like the state of alert buttons/snack bars, etc.
Filters over Mixins.
Mixins lead to implicit dependencies, namespace clashes, etc. You can find more about that here. Some Mixins can be converted to Filters.
//dateMixin.js
export default {
methods: {
formatDate(date) {
return date.split("T")[0];
}
}
};
In our SFC, we have:
<template>
<h3>{{formatDate(date)}}</h3>
</template>
<script>
import dateMixin from "./dateMixin";
export default {
mixins: [dateMixin],
data() {
return {
date: "2019-08-07T00:00:00"
};
}
};
</script>
With filters,
//main.js
import Vue from "vue";
Vue.filter("formatDate", value => value.split("T")[0]);
In our SFC,
<template>
<h3>{{date | formatDate}}</h3>
</template>
<script>
export default {
data() {
return {
date: "2019-08-07T00:00:00"
};
}
};
</script>
Use Modules to separate the different services on your application.
Instead of having everything needed by our state in one object, we can segregate them into modules.
Instead of
const state = {
token: "",
amount: "",
firstname: "",
lastname: "",
email: "",
isLoggedIn: ""
};
We can divide our services into authentication, profile-management and wallet.
Our folder structure would look like
modules
authentication
index.js
profile-management
index.js
wallet
index.js
In the index.js file, we can have the state that matters to that service.
//modules/authentication/index.js
const state = {
token: '',
isLoggedIn:''
}
...
Then when we initialize our store, we can add all the modules.
export const store = new Vuex.store({
state: {
//something general
isAppBusy: false
},
modules:{
authentication,
profile-management,
wallet
}
});
Conclusion
These are my thoughts on how to make the structure of Vue code better. If you have extra additions or subtractions, I'll like to see it in the comments π.
Top comments (7)
I enjoyed using vuex for a shop I was building, but I am writing a portfolio now, I opted out of vuex, and yes I need a certain level of abstraction, but do you know what is better than local state management? No state, or atleast remote data. I have cut down on the need to use any of this with a headless CMS and graphql.
Out of curiosity, what headless CMS are you using? Any articles you can recommend on this sort of stack? I've been very interested in giving GraphQL a go.
Soo the post will cover my thoughts on 2 headless cms's
Headless CMS + JavaScript renderer
Adam Crockett γ» Sep 24 γ» 2 min read
Nice, that works also. The requirements of the application will justify how much a state management library is needed. Is there a repository for your shop ?
I can't share the shops sorry it's unde private control. But that is the vux stuff. If you are interested in my portfolio in Vue with graphcm I can share this WIP
Nice article, thank you. I think itβs even better to use mapState instead of a getter when the variable is not changed in the getter. Getters are actually provided to adjust a variable before returning it.
True, When there are so many getters and things get verbose, mapState works fine, but mapState actually helps you create computed getter properties under the hood. So you're still using getters. I saw that here, vuex.vuejs.org/guide/state.html