Nicky Christensen
May 4 · 11 min read

I’ve been doing Vue for some time now.

Along the way, I’ve come across a lot of learnings, a lot of gotcha’s and a lot of yay moments.

As a result of this, I would like to share my advice, tips and best practices to you, if you’re in the moment of building a new Vue application. What you should do, what you should avoid, and generally just some plain old good advice 😉


New to Vue?

If you are completely new to Vue, this article will most likely not provide you any great value, as you need to have some basic knowledge in Vue to understand some of the things I’m covering in this post.

I’ll recommend that you learn Vue from the some of the best courses out there — I’ve provided some links to useful resources at the bottom of this article


Anyway, let’s get to it.

Install VueDevtools

When working with Vue, it’s impossible to live without VueDevtools. This is a Chrome/Firefox extension you can install, which makes debugging your Vue application a breeze — https://github.com/vuejs/vue-devtools

Install VuePerformanceDevtool

This Chrome extension allows you to inspect the performance of Vue Components — A good and useful tool: https://chrome.google.com/webstore/detail/vue-performance-devtool/koljilikekcjfeecjefimopfffhkjbne

When installed, you need to add this to your code:

Vue.config.performance = true;

Component Communication

Components can communicate in different ways in Vue. You can use props to pass down data to your components

<my-component :firstProp="someValue"></my-component>

This is just a one-way communication. If you want to inform your parent component that someValue has changed, you can use events.

...
export default {
methods: {
onClick() {
this.$emit('nameOfEvent', someValue);
}
}
}

You can in your parent component, react to the event you just emitted

<my-component :firstProp="someValue" @nameOfEvent=”doSomething”></my-component>

The built in $emit() method is only used when you need to have child/parent communication.

If you need more complex communication, you can use the EventBus (See this article: https://alligator.io/vuejs/global-event-bus/) or Vuex.
The EventBus is meant for smaller applications where you don’t have a lot of shared state across components. If you know your application is going to be complex, go with Vuex instead.

Use Vuex for state management

Use Vuex if you are going to build a medium/large application. When having a data heavy application and need to share and manage state across your application, use Vuex.
As mentioned before, the EventBus is meant for small applications. If you find yourself using it in a medium/large sized application, you will eventually run into problems.

I remember the first Vue application I built — I started out using the EventBus, but that quickly became confusing and unmaintainable — And the refactoring was hell.

Vuex, Go learn it, and learn it good. Make use of it ASAP if you start to see your application grow — This is really a great addition when you need to scale your Vue application.

  • Get to know the concept of state, getters, mutations and actions
  • Look into Vuex modules
  • Learn how to create a good structure, as Vuex doesn’t give you any restrictions
  • Learn how the “strict” mode works
  • Add the Vuex Cheatsheet as a bookmark to your browser: https://github.com/vuejs-tips/vuex-cheatsheet

Additional resources on Vuex:

https://vuex.vuejs.org/
https://vuejsdevelopers.com/2017/05/15/vue-js-what-is-vuex/

Code Splitting

Performance is a big topic these days, and with applications getting larger and more complex, we need to make our applications as fast as possible. If you can, utilize code splitting. This is a great way of reducing your main javascript bundle size, and thereby improve the initial load of your application.

const Loader = () => import(/* webpackChunkName: "aChunkName" */'../path/to/component.vue');

There are a few other patterns you can use — Check out this article from Anthone Gore: https://vuejsdevelopers.com/2017/07/03/vue-js-code-splitting-webpack/

Shortcut component registration

When working in components, we might need to import other components. I’ve seen many times where components gets registered like this:

import MyAwesomeComponent from './my-awesome-component.vue';...
components: {
'my-awesome-component': MyAwesomeComponent
}

This is not wrong at all, but there is a nice little shorthand for doing this:

...
components: {
MyAwesomeComponent,
MyAwesomeComponentTwo,
MyAwesomeComponentThree
}

Shortcut for registering components globally

When registering components globally, the common pattern is that we import our component and then use vue.component() to register it.

import ComponentA from './component-a.vue';
import ComponentB from './component-b.vue';
import ComponentC from './component-c.vue';

Vue.component('component-a', ComponentA);
Vue.component('component-b', ComponentB);
Vue.component('component-c', ComponentC);
...

If you have a lot of components this can get a tedious task. You can easily create a function that can handle the component registration for you.

Simply create an object with your components and loop through the object and do the registration

const ctors = {};

const components = {
ComponentA,
ComponentB,
ComponentC
};

//Attach component to vue globally - NOTE: Remember to define a name in your component...
Object.keys(components).forEach(function (key) {
const component_name = components[key].name;
if (component_name) {
ctors[component_name] = Vue.component(component_name, components[key]);
} else {
throw new Error('It seems you forgot go give your component a name...');
}
});

Avoid registering all components as global components

Global components should only be used for base components which you use all time in your application.
This could be components such as a Buttons/Inputs etc.

Specific components should be imported in other components, by using async components if possible. (Components in components)
This will keep your bundle size small and your application more performant. See the section about code splitting in this article.

Validate your props

When passing props to a component, you should IMHO always do some validation. If you pass props without defining which type it should be (String, Array, Object……), it can be very hard for other team members to know what to pass.

Learn more about prop validation here: https://vuejs.org/v2/guide/components-props.html

Routing

When building a SPA application, you most likely need client-side routing. Vue doesn’t ship with built-in routing. Vue however does have an official plugin you can make use of — VueRouter. It’s super simple to work with and provides all the functionality you need to create a powerful application.

NOTE: If you are using the VueCLI, you can add it to your application very easy, without having to install in manually through npm-install vue-router

Official docs here: https://router.vuejs.org/

URL changes, but view doesn’t update

When working in a SPA, you will most likely be reusing component in views. Imagine you’re on a blog post, and from there go to another blogpost, you would expect the content to change to the new content, but it doesn’t.

This is most likely a result of using the same component, and Vue will then reuse the instance. The this.$route in the component will change but all lifecycle hooks like created(), beforeMounted() and mounted() hooks won’t be re-instantiated.
For this problem, there are a few solutions:

To force Vue to create a new component instance you can set a unique key in the <router-view>

<router-view :key="$route.fullPath">

Or setup a watch handler so you can react to a route change

watch: {
"$route.params.somevalue": {
handler(somevalue) {
// do stuff
},
immediate: true
}
}

You are (almost) forced to have a root node.

By default, each component in Vue needs to have a single root node. This can unfortunately lead to some headaches, as we don’t necessarily always want to have a wrapping div in our components:

<template>
<div> <!-- The root -->
<span></span>
<span></span>
</div>
</template>

So by default you can’t do

<template>
<span></span>
<span></span>
</template>

This will return an error:
Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.

There is a way to get around this by using functional components, which Anthony Gore has written a great article about: https://vuejsdevelopers.com/2018/09/11/vue-multiple-root-fragments/

Form Validation made easy

We all know that building form validation from scratch can be somewhat cumbersome, and very time consuming.
Luckily, there is a few great form validation plugins for Vue out there. I definitely recommend that you take a look a either Vuelidate or VeeValidate. Both are great and will save you a lot of time when working with forms.

Get to know Vue’s lifecycle hooks.

To utilize the power of Vue, I strongly recommend that you get to know the lifecycle hooks.

I.e: you can’t access a property in your data if you are trying to access it when using the beforeCreated() hook, and you cant get a ref element in the created() hook as the template isn’t mounted to the DOM yet.

Avoid manipulating the DOM directly

A good rule of thumb when working with Vue, is that you should by all means avoid accessing the DOM directly.
One of the main purposes with a javascript framework like Vue is to avoid messing directly with the DOM, like you would do with Vanilla JS or jQuery.

Instead you should make use of $refs. This is a clean way of accessing the DOM, and the Vue way. It’s also more maintainable, as you won’t have to deal relying on elements with specific class names, ids etc…

Learn more about using $refs in this short video: https://www.youtube.com/watch?v=rSyFM2FANtk

Working with data

Every application most likely needs to communicate with some sort of external service at some point, either to fetch/post data.
For simple operations, and depending on which browsers you need to support, using the native fetch() method might be enough.
If not, I recommend you use the axios npm package. It’s one of the most popular packages, and is widely adopted by the React / Vue community.

Looping

We can easily loop through an array of objects with v-for

<div v-for="item in items" v-bind:key="item.id">
<!-- content -->
</div>

Always remember to add a :key to your list unless you have a very simple array. This is the recommended way as you can gain performance whenever Vue needs to update a components in your loop, as it is used as an identifier. If you provide duplicate keys, Vue will give you a warning in the console.

Learn more about keys here: https://vuejs.org/v2/api/#key

Computed properties vs Methods

Computed properties are the goto when you want to manipulate data that exists in your Vue instance — another bonus that they are really performant as they are also cached from their reactive dependencies.

data:{
names: ["Leonardo", "Donatello", "Rafael", "Michaelangelo"]
},
computed:{
startsWithD(){
return this.names.filter(name => name.startsWith("D"))
}
}

<p v-for="(name, index) in startsWithD" :key="index">{{name}}</p>

A good rule of thumb. If you have complex computed properties, split them into many simple computed properties., this is easier to test, more maintainable and more readable.

A method is a function bound to the Vue instance. It will only be evaluated when you explicitly call the method, just like a regular javascript method.

data:{
names: ["Leonardo", "Donatello", "Rafael", "Michaelangelo"]
},
computed:{
startsWithD(){
return this.startWithCharacter("D")
},
startsWithL(){
return this.startWithCharacter("L")
}
},
methods:{
startWithCharacter(char){
return this.names.filter(name => name.startsWith(char))
}
}

Learn more about computed properties here: https://vuejs.org/v2/guide/computed.html

Know the power of mixins

When we are building our applications, we often need to reuse functionality across across components. Mixins are a great way to do this. This means if I create a component that holds X different methods/lifecycle hooks/local state etc, I can create a mixin and make other extend this mixin, making the methods and what not available in our new component.

Learn more about mixins in the docs: https://vuejs.org/v2/guide/mixins.html

Know the power of filters

Filters are great, especially when you are dealing with date-formatting, currencies etc. Filters enables you to create global or local formatting functions which you can use. Widely inspired by AngularJs

filters: {
formatDate: function (date) {
if(date) {
//format using date-fns
return format(
new Date(date),
'DD.MM.YYYY'
)
} else {
return '--';
}
}
}

Lean more about creating filters here: https://scotch.io/tutorials/how-to-create-filters-in-vuejs-with-examples

Utilize the built in modifiers

A real cool feature in Vue, is the built-in modifiers. There are different modifiers which you can use in different scenarios. I urge you to learn and utilize these. Get to know them and it will save you a lot of time when writing your code.
In this article, I won’t go into detail on how you can use them, as the documentation of Vue describes this in great detail

Form modifiers / https://vuejs.org/v2/guide/forms.html#Modifiers

  • .lazy
  • .number
  • .trim

Event Modifiers / https://vuejs.org/v2/guide/events.html#Event-Modifiers

You probably caught yourself using event.preventDefault() a few times if you had to deal with submit / click events.
Vue provides us with a few event modifiers, so we don’t have to write that code ourselves:

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive

Key Modifiers

  • .enter
  • .tab
  • .delete
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

Another cool thing is that you can define your own custom key modifiers by using the global config.keyCodes

Good structure!

Vue doesn’t come with any default way of structuring your application (Unless you are using Nuxt), which can be good, but can also become very messy if you aren’t an organized person.

Because of this flexibility it’s very much up to you, or your team to create a good and understandable structure that all team members can understand and work with.

I can’t stress out enough how important I personally think it is to think about how you are going to setup a good and meaningful structure. Changing it later becomes a hazzle… Trust me…. 😊

More tips on structuring for Vue application for large scale projects here: https://dev.to/maxpou/3-tips-for-scaling-large-vuejs-application-2edi

Clean up after yourself.

If you are building a SPA you can build up memory usage and if you don’t remember to remove custom events, instances, intervals, etc, eventually your application will become slow and unresponsive.

This could look something like:

created() {
refreshUserLoginTokenInterval(); //At created we start an interval to refresh
},
beforeDestroy () {
destroyUserLoginInterval(); //Before component is destroyed, we clean up
}

The Vue docs also holds some valuable information about avoiding memory leaks:
https://vuejs.org/v2/cookbook/avoiding-memory-leaks.html

Add multiple classes to an element

This is something I find myself doing a lot. Luckily Vue makes it very easy to add a dynamic class to an element

//Add class red if isError is true
<div :class=”{'red': isError}”></div>

But how do you add multiple classes? There a few different approaches you can use, but the most common and easy is this:

// Add to classes if two properties return true
<div :class="{'red': isError, 'text-bold': isActive }”></div>

You can also add multiple classes based on a computed function — Here’s a great example on this: https://bytutorial.com/blogs/vuejs/how-to-bind-multiple-css-classes-in-vuejs



Pheeeew, you got all the way through. I could have written even more, but a person can only take in so much knowledge at a time 😊

Vue has a lot to offer and is a really great joy to work with, and even more fun if you know some of the best practices, gotchas and useful tools.

I hope you enjoyed the article, and are up for some additional articles on Vue in the future 😊

If you’d like to catch up with me sometime, follow me on Twitter | LinkedIn | Facebook or simply visit my portfolio website (That is however in Danish)

Vue.js Developers

Helping web professionals up their skill and knowledge of Vue.js

Nicky Christensen

Written by

Senior Frontend Developer @ Creuna Denmark — VueJS Fanboy — In love with most frontend related stuf — nickychristensen.dk / https://twitter.com/nickycdk

Vue.js Developers

Helping web professionals up their skill and knowledge of Vue.js