8 Top VueJS Best Practices

Frank Fischer
DeepCodeAI
Published in
5 min readJun 26, 2020

We constantly scan open source repos to find changes that indicate a possible issue pattern. As soon as we see these patterns, we train the system to fill the parameter space aka find all possible values for any parameter in the rule that addresses this pattern.

Doing so for VueJS, we found some best practices that we want to share here. But the list below goes beyond static analysis finds and includes general best practices, too.

Do you want to get your VueJS project checked out? Sure, do so by clicking here. It only takes a few seconds. You can also include DeepCode into your daily workflow by using our IDE PlugIns such as the Visual Studio Code Extension

Number 1: Do Not Change Props

Props are to communicate from the parent component to a sub-component and it is a ONE WAY TICKET! But we see props being changed in projects again and again. (Same issue on React by the way) There are three main reasons why you try to change props:

  1. Because you need to save the local state. So use data instead.
  2. Because you want to change the overall state. Use custom events to communicate with the parent component. It keeps the state and communicates changes back to the child components.
  3. Because you — as I did back in the days, mea culpa — are not aware of the shallow copy used in JavaScript / TypeScript. For complex objects, references are copied. See here for more on the topic. Make sure you really copy things.

By the way, DeepCode is aware of props and will flag mutation - even on substructures.

Number 2: Be Aware of the Lifetime of Your Component

It is always a good idea to familiarize yourself with the life cycle model of the framework of your choice. Have a look at the life cycle model in VueJS and then we will share a few observations:

Source — Life Cycle Diagram

  1. You can see three main phases: A construction phase when the component is generated and set up, an update cycle when the component reacts on data changes, and a tear-down phase when the component is destroyed. The lifecycle graph gives you an overview when which event is called.
  2. See what happens to el ? Every event before mounted should not access el as it is not created as of yet. DeepCode is aware of this and reports these kinds of issues.
  3. See mountedand beforeUpdate?? Above drawing is a bit misleading here. Even in the construction phase the update cycle is run and beforeUpdate is called.

Overall, here is good info on the lifecycle hooks in VueJS.

Number 3: Be Aware of Camel vs Kebab Casing

There are various ways to combine words in software development. Pascal, Snake, Spine, Camel or Kebab-casing to name some. JavaScript and TypeScript are case-sensitive aka Counter is not equal to counter. As HTML, in general, is case-insensitive; especially of interest here are HTML attributes (by the way, XHTML is XML and such case sensitive - see for background), VueJS is in a kind of dilemma as it spans the two worlds.

Just as a reminder:

camelCase

Start with lower-case and combine subsequent words by capitalize them. Example: thisIsACamelCase.

PascalCase

Start with an upper-case and combine subsequent words by capitalize them. Example: ThisIsAPascalCase.

kebab-case

Write everything in lower-case and separate words by hyphens. Example: this-is-a-kebab-case.

To help you out, VueJS translates camelCase prop names into kebab-cased equivalent. But whenever things happen automatically, you need to be aware not to fall into a trap.

Vue.component('my-component', {
props: ['myPropertyMessage'], // camelCase in JavaScript
template: '<h1>{{myPropertyMessage}}</h1>'
})

…will translate to…

<!-- kebab-case in HTML -->
<my-component my-property-message="Hello World!"></my-component>

So: Declare props with camelCase and use Kebab Case in Templates. See also here for more info.

Secondly, it is also a best practice to use kebab-casing in custom events:

this.$emit('trigger-action')<parent-component @trigger-action='handleTrigger()' />

Finally, the VueJS Style Guide requires you to use multi-word component names and strongly recommends using PascalCase in single-file components.

Number 4: Data needs to return a Generator Function

One of the essential things in the VueJS style guide: data needs to provide a generator function (see here). The reason is simple: VueJS needs to get a fresh copy of the dataobject for each instance of a component. Otherwise, components might overwrite each other's state. Which also explains why it is ok to use an object in the app component as it per definition only exists once.

Below is an example of how you should do it:

Vue.component('my-component', {
data: function () {
return {
counterIncrease : 1
}
}
})
//In a vue file
export default {
data() {
return {
counterIncrease : 1
}
}
}

Number 5: Don’t use v-if With v-for Elements

Again, clear advice from the style guide:

<div v-for='product in products' v-if='product.category == 4'> </div>

The reason is that VueJS assigns a higher priority of the v-for than the v-if. This leads to a performance issue as the loop would run and filter inside instead of filter first.

The best practice here is to reduce the size to iterate over before the iteration by using a computed property:

computed: {
onSaleProducts: function() {
return this.products.filter(function (product) {
return(product.category == 4)
})
}
}

Number 6: v-if/v-else-if/v-else without key

VueJS tries to be as optimal as can be regarding updating and re-rendering. In the case, that two elements of the same type — one shall be rendered, one not — VueJS would patch up the existing one instead of adding a new and deleting the old. Obviously, this could lead to strange effects given the two components should not be seen as the same. Example:

<div v-if="error"> // bad: no key
Error: {{message}}
</div>
<div v-else>
{{ results }}
</div>
<div v-if="error key="search-status"> //good: key is set
Error: {{message}}
</div>
<div v-else key="search-results">
{{ results }}
</div>

Again, see the style guide.

Number 7: Props should be as detailed as possible

Two main reasons: First, this acts as a documentation of your component. Secondly, it helps to VueJS to provide warnings on possible issues.

props: ['status'] // Bad - maybe good enough for prototypingprops: {
status: String, // Better
required : true
}

This gives VueJS the opportunity to check on the provided type. Even better, see next …

Number 8: Props Validation Helps When Handing On Components

VueJS provides a mechanism to check on properties provided by the parent component. Especially when building components to be used by others, it makes sense to ensure the props are complete and well-formed.

props: {
status: {
type: String,
required: true,
validator: function(value) {
return [
'initiated',
'to do',
'in progress',
'done'].indexOf(value) !== -1
}
}
}

We hope this gave you some useful hints. Let us help you even more and use our tool on your repos. Get started on DeepCode.AI.

--

--