Categories
Vue Best Practices

Vue Best Practices — Recommended Syntax

Vue is an easy front end framework to work with. It lets us create apps easily.

However, there are still many things that we should look out for when we write apps with them.

In this article, we’ll look at the best practices for using the recommended syntax.

Attribute Hyphenation

We can hyphenate our attributes so that it’s consistent with HTML attributes.

For instance, we can write:

<FooComponent foo-prop="prop" />

instead of:

<FooComponent fooProp="prop" />

Component Name Casing

Names for components should be PascalCase or kebab case.

Vue can translate between either case.

For instance, we can write:

<FooComponent />

or:

<foo-component />

Closing HTML Brackets in a New Line

Having closing HTML brackets in a new line makes it easier to change and read.

Therefore, we may consider putting them on a new line.

For instance, we can write:

<div  
  id="foo"  
  class="bar"  
>   
  <!-- //... -->  
</div>

instead of writing:

<div  
  id="foo"  
  class="bar">   
  <!-- //... -->  
</div>

No Space Before Closing Bracket Tags

We shouldn’t have space before closing bracket tags.

For instance, we shouldn’t have:

<div ></div>

Instead, we write:

<div></div>

HTML End Tags

We should have end tags for non-self-closing tags.

For instance, we should write:

<div></div>

instead of:

<div>

Indentation

We should have some indentation in our HTML.

It makes the code easier to read and change.

For instance, we can write:

<div class="bar">  
  Hello.  
</div>

Quotes

Quotes should be added to HTML attribute values.

For instance, we can write:

<img src="./photo.png">

or:

<img src='./photo.png'>

Single or double quotes are both fine.

This way, we won’t have syntax errors when we’re passing props instead of setting HTML attribute values.

Self-Closing Tags

If a component doesn’t have any content, it can either be self-closing or not.

The self-closing syntax isn’t supported in HTML spec, so we shouldn’t use it when we’re writing Vue code without a build step.

For instance, we can write:

<BarComponent></BarComponent>

which isn’t self-closing or:

<BarComponent />

which is self-closing.

Maximum Number of Attributes Per Line

We don’t want to have so many attributes in a line that people have to scroll horizontally to read everything.

Therefore, we may want to limit the attributes in one line.

For instance, we may want to have one attribute per line, so we write:

<FooComponent  
  foo="1"  
  bar="2"  
  baz="3"  
/>

HTML Content Newline

HTML content should be in its own line in between the tags.

This way, we know where the content exactly is without looking too hard.

For instance, we can write:

<div>  
  multiline  
  content  
</div>

Mustache Interpolating Spacing

We should have some space between the mustache and the expression that’s inside it.

It’s easier to read if we have one space character before and after the expression.

For instance, we can write:

<div>{{ msg }}</div>

This way, the expressions are easy to find.

No Multiple Spaces

Having a bit of space is good, but we shouldn’t have too many spaces since it’s just a waste of screen real estate.

For instance, the following is good”

<i  
  :class="{  
    'fa-angle-up': isExpanded,  
    'fa-angle-down': !isExpanded,  
  }"  
/>

There’s one space after the colon, which is enough to make the keys and value easy to read.

No Spaces Around Equal Signs in Attribute

HTML5 allows space around equal signs, but it’s easier to read without the spaces and they’re grouped better without the spaces.

Therefore, we write:

<div class="foo"></div>

instead of:

<div class = "foo"></div>

No Template Variable Shadowing

We shouldn’t have variable declarations in a nested element or component that’s identical to the variable declaration in the outer element or component.

For instance, we shouldn’t have something like the following:

<div>  
  <div v-for="x in 5">  
    <div v-for="x in 10"></div>  
    <div slot-scope="{ x }"></div>  
  </div>  
</div>

We have x that’s both declared in the outer v-for and the inner one.

That will just confuse Vue and ourselves.

We should name them differently and reduce nesting whenever possible.

So we should write:

<div>  
  <div v-for="a in 5"></div>  
  <div v-for="b in 10"></div>  
</div>

Conclusion

There are lots of syntax errors that we should avoid in templates.

Also, the formatting of the attributes can be better by sticking to spacing and indentation conventions.

Categories
Vue Best Practices

Vue Best Practices — Directives

Vue is an easy front end framework to work with. It lets us create apps easily.

However, there are still many things that we should look out for when we write apps with them.

In this article, we’ll look at the best practices for using directives.

Make Sure v-html is Valid

When we use the v-html directive, we shouldn’t have any modifiers added to it.

And we should have an argument with the expression that stores the HTML code as a string.

For instance, we can write:

<div v-html="foo"/>

where foo is a variable.

Make Sure that v-if is used Properly

v-if shouldn’t have modifiers.

But it should have an argument with the expression to check whether to display anything.

For instance, instead of writing:

<div v-if:abc="foo"/>

or:

<div v-if/>

We write:

<div v-if="foo"/>

Make Sure v-model is Used Properly

v-model may have some modifiers.

The argument is also required so that it binds to the variable indicated in the argument.

Also, they should be added to input controls.

For instance, we can write:

<input v-model="foo">

or:

<input v-model.lazy="foo">

Make Sure that we use v-on Properly

v-on should be used properly to bind to variables.

It can have arguments to run an event handler when an event is triggered.

Also, it can have no arguments to pass events from a child to a parent.

For instance, we can write:

<div v-on="foo"/>

or:

<div v-on:click="foo"/>

@ is short for v-on , so we can write:

<div @click="foo"/>

or:

<div @click.right="foo"/>

where foo is the event handler to run.

Make Sure that v-once is used Properly

v-once indicates that a component or element should only be rendered once.

It takes no arguments or modifiers.

The element or component will be treated as static elements on subsequent rendered.

For instance, we use it by writing:

<div v-once/>

Using v-pre Properly

v-pre is another directive that doesn’t take any argument or modifiers.

It’s used to skip compilation for the element with this directive and all its children.

Therefore, we can use it to display raw Vue or other kinds of code.

We use it by writing:

<span v-pre>{{ raw code }}</span>

Make Sure we use v-show Properly

v-show is used to display something conditionally by showing or hiding it with CSS.

It takes an argument with the boolean expression that’s checked for displaying something if it returns true .

For instance, we use it by writing:

<div v-show="foo"/>

Using v-text Properly

The v-text is equivalent to the mustache for interpolating expression within an element.

It takes an argument for the expression return value to display.

For instance, we can write:

<span v-text="msg"></span>

Which is the same as:

<span>{{msg}}</span>

No Custom Modifiers on v-model

v-model only takes a few modifiers.

It can take a few modifiers like trim to trim leading and trailing whitespaces.

lazy for lazy evaluation.

And number to convert the inputted value to a number.

However, it doesn’t accept any custom modifiers.

So to use v-model properly, we write:

<input v-model="foo" />

or:

<input v-model.trim="foo" />

or:

<input v-model.lazy="foo" />

or:

<input v-model.number="foo" />

No Multiple Template Root

Our template should only have one root element.

Otherwise, Vue will throw an error.

For instance, we can write:

<template>foo bar</template>

But we can’t write something like:

<template>
  <div v-for="todo in todos"/>
</template>

since it renders multiple items.

Instead, we write:

<template>
  <div>
    <div v-for="todo in todos"/>
  </div>
</template>

v-bind.sync should be Used Properly

v-bind.sync needs to be used properly.

v-bind.sync doesn’t need a value prop in the child.

It uses the same prop as we have in the parent.

For instance, we can use it as follows:

App.vue

<template>
  <div id="app">
    <Input :msg.sync="msg"/>
    <p>{{msg}}</p>
  </div>
</template>

<script>
import Input from "./components/Input";

export default {
  name: "App",
  components: {
    Input
  },
  data() {
    return {
      msg: "Hello Vue!"
    };
  }
};
</script>

Input.vue

<template>
  <input :value="msg" @input="$emit('update:msg', $event.target.value)">
</template>

<script>
export default {
  name: "Input",
  props: {
    msg: String
  }
};
</script>

:msg.sync passes the value of msg to the child and allows it to emit some with update: name.

We have the value prop set to the msg prop value passed from the parent in Input.vue .

Then we emit an update:msg event to emit msg back to the parent.

Now when we type on the screen, we’ll see what we typed displayed.

Conclusion

Making sure that we use Vue directives properly is a big part of writing Vue apps that don’t have bugs.

We should make sure that the syntax is correct and no typos in our modifiers or arguments if they’re included.

Categories
Vue Best Practices

Vue Best Practices — Props and Computed Properties

Vue is an easy front end framework to work with. It lets us create apps easily.

However, there are still many things that we should look out for when we write apps with them.

In this article, we’ll look at some essential rules that we should follow when we’re building our Vue apps.

Require Valid Default Prop

We should have a default prop value for our props to prevent issues that arise if we forgot to pass in a prop.

Also, we should make sure that the default prop type matches the type of the prop specified.

For instance, instead of writing:

<template >  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App",  
  props: {  
    propA: {  
      type: String,  
      default: {}  
    }  
  }  
};  
</script>

We write:

<template >  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App",  
  props: {  
    propA: {  
      type: String,  
      default: "foo"  
    }  
  }  
};  
</script>

A Computed Property Should Return Something

Computed property functions should always return something.

For instance, instead of writing:

<template >  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App",  
 computed: {  
   foo(){  
     if (Math.random() < 0.5){  
       return 'foo'  
     }  
   }  
 }  
};  
</script>

We should write:

<template >  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App",  
  computed: {  
    foo() {  
      return "foo";  
    }  
  }  
};  
</script>

Add the exact Modifier on v-on When There are Multiple v-on Directives

If there’s another v-on handler in our component or element, then we should add the exact modifier to the directive so that only the given event is handled.

For instance, instead of writing:

<template >  
  <div id="app">  
    <button v-on:click="onClick" v-on:click.ctrl="onClick"></button>  
  </div>  
</template>  
<script>  
export default {  
  name: "App",  
  methods: {  
    onClick() {  
      //...  
    }  
  }  
};  
</script>

We write:

<template >  
  <div id="app">  
    <button v-on:click.exact="onClick" v-on:click.ctrl="onClick"></button>  
  </div>  
</template>  
<script>  
export default {  
  name: "App",  
  methods: {  
    onClick() {  
      //...  
    }  
  }  
};  
</script>

Template Should be the Root of the Component Template

We should make sure that we don’t have extra things in our template element.

For instance, instead of writing:

<template v-if'foo'>  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App"  
};  
</script>

We wrote:

<template>  
  <div id="app"></div>  
</template>  
<script>  
export default {  
  name: "App"  
};  
</script>

Make Sure the v-bind is Valid

v-bind is valid if it has an attribute and has no invalid modifiers.

For instance, we shouldn’t have:

<div v-bind/>

or:

<div v-bind:cc.bbb="foo"/>

Instead, we write:

<div v-bind="foo"/>

or:

<div :aaa="foo"/>

or:

<div v-bind:aaa="foo"/>

assuming that aaa exists.

Make Sure that v-cloak is Valid

A valid v-cloak directive doesn’t have arguments or modifiers.

So we should write:

<div v-cloak/>

Anything else isn’t valid.

Make Sure that v-else-if is Valid

A valid v-else-if can’t have modifiers.

Also, it must have an attribute value.

It must go after an element with v-if as its sibling.

For instance, instead of writing:

<div v-else-if/>

or:

<div v-else-if:aaa="bar"/>

We write:

<div v-if="foo"/>     
<div v-else-if="bar"/>

Make Sure that v-else is Valid

v-else shouldn’t have any arguments or modifiers.

It must go after an element with v-if or v-else-if as its sibling.

For instance, we should write:

<div v-if="bar"/>     
<div v-else/>

instead of:

<div v-else:aaa/>     
<div v-else.bbb/>

Make Sure Our v-for Directive is Valid

A v-for directive should have an argument, but no modifiers.

Also, we need to add the key prop to elements rendered by v-for .

For instance, instead of writing:

<div v-for/>

or:

<div v-for.c="todo in todos"/>

We write:

<div       
  v-for="todo in todos"       
  :key="todo.id"     
/>

The :key prop or v-bind:key directive is required.

Conclusion

We should make sure that our directives are used properly.

If they need modifiers or arguments, then we add them. Otherwise, we don’t.

If we have multiple v-click directives, then we need the exact modifier on the broader one so that the other one can pick up the specified user events.

v-for directives shouldn’t have modifiers but it should have arguments.

Categories
Vue Best Practices

Vue Best Practices — Templates and Variables

Vue is an easy front end framework to work with. It lets us create apps easily.

However, there are still many things that we should look out for when we write apps with them.

In this article, we’ll look at some essential rules that we should follow when we’re building our Vue apps.

No Unused Components

We shouldn’t have unused components lying around in our project.

So instead of writing:

<template >
  <div id="app"></div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
  name: "App",
  components: {
    HelloWorld
  }
};
</script>

We should write:

<template >
  <div id="app">
    <HelloWorld/>
  </div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
  name: "App",
  components: {
    HelloWorld
  }
};
</script>

No Unused Variable Definitions in v-for

When we define a v-for loop, we should use all the variables that are defined.

For instance, instead of writing:

<template >
  <div id="app">
    <ol v-for="i in 5">
      <li>foo</li>
    </ol>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>

We should write:

<template >
  <div id="app">
    <ol v-for="i in 5">
      <li>{{ i }}</li>
    </ol>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>

Don’t Use v-if and v-for Together

v-for and v-if shouldn’t be used together since it’s slower than using computed properties.

We should use competed properties to render fewer items rather than using v-if to check if each item should be rendered.

For instance, instead of writing:

<template >
  <div id="app">
    <ul v-for="a in arr" v-if="a % 2 === 0" :key="a">
      <li>{{ a }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      arr: [1, 2, 3, 4, 5]
    };
  }
};
</script>

We write:

<template>
  <div id="app">
    <ul v-for="a in evenNums" :key="a">
      <li>{{ a }}</li>
    </ul>
  </div>
</template>
<script>
export default {
  name: "App",
  computed: {
    evenNums() {
      return this.arr.filter(a => a % 2 === 0);
    }
  },
  data() {
    return {
      arr: [1, 2, 3, 4, 5]
    };
  }
};
</script>

Add the is Prop to the Component component

To display components dynamically, we’ve to use the component component to display items.

The is prop sets the name of the com[onent to display.

For instance, instead of writing:

<template >
  <div id="app">
    <component/>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>

We write:

<template >
  <div id="app">
    <component :is="name"></component>
  </div>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
  components: {
    HelloWorld
  },
  name: "App",
  data() {
    return {
      name: "HelloWorld"
    };
  }
};
</script>

Prop Types Should be a Constructor

We should put constructors as the values of the props property to make sure that they’re an instance of some constructor.

For instance, instead of writing:

<template >
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  props: {
    name: "String"
  }
};
</script>

We should write:

<template >
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  props: {
    name: String
  }
};
</script>

It can also be an array if our prop can more than one type:

<template >
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  props: {
    name: [String]
  }
};
</script>

A Render Function Should Return Something

A render function should return something that we want to render.

For instance, instead of writing:

Vue.component("hello", {
  render(createElement) {
    if (Math.random() < 0.5) {
      return createElement("div", "hello");
    }
  }
});

We should write:

Vue.component("hello", {
  render(createElement) {
    return createElement("div", "hello");
  }
});

We make sure that a render function always returns something.

Add a key Prop to Items Rendered by v-for

We need the key prop to anything that’s rendered by v-for so that Vue can keep track of it properly.

For instance, we should write:

<template >
  <div id="app">
    <div v-for="a in 5">{{a}}</div>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>

We write:

<template >
  <div id="app">
    <div v-for="a in 5" :key="a">{{a}}</div>
  </div>
</template>
<script>
export default {
  name: "App"
};
</script>

Now Vue can keep track of the rendered items properly.

Conclusion

We should make sure that we have a key prop added to whatever is rendered by v-for .

Unused components should be removed from our code.

Render functions should always return something to render.

And prop types should be a constructor. Otherwise, the prop type check won’t work.

Categories
Vue Best Practices

Vue Best Practices — Most Important Changes

Vue is an easy front end framework to work with. It lets us create apps easily.

However, there are still many things that we should look out for when we write apps with them.

In this article, we’ll look at some essential rules that we should follow when we’re building our Vue apps.

No async Function for Computed Properties

The functions we use for computed properties should be synchronous.

If we use async functions, unexpected behavior may occur.

If we ned computed properties to be async, then we can use plugins to use them.

For instance, we should write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  computed: {
    reversedMsg() {
      return this.msg
        .split("")
        .reverse()
        .join("");
    }
  },
  data() {
    return { msg: "foo" };
  }
};
</script>

No Duplicate Keys in Field Names

We shouldn’t have duplicate field names in our component object.

This applies to the whole object. So we shouldn’t have the same name in methods or data for example.

Instead of writing:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  computed: {
    foo() {
      return 'bar'
    }
  },
  data() {
    return { foo: "foo" };
  }
};
</script>

We should write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  computed: {
    foo() {
      return "bar";
    }
  },
  data() {
    return { bar: "foo" };
  }
};
</script>

No Duplicate Attributes

We shouldn’t have duplicate attributes in our templates.

For instance, instead of writing:

<template>
  <div id="app">
    <div :id="id"></div>
    <div id="id"></div>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      id: "id"
    };
  }
};
</script>

We write:

<template>
  <div id="app">
    <div :id="id"></div>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      id: "id"
    };
  }
};
</script>

Don’t Overwrite Reserved Keys

We shouldn’t write keys that have the same names as reserved keys.

For instance, we shouldn’t write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  props: {
    $el: String
  }
};
</script>

We have an $el prop, which is a reserved key.

We shouldn’t have that so we won’t get unexpected results.

No Shared Component State

The data property should have a function instead of the object as its value.

If we have an object, then the state will be shared.

Therefore, instead of writing:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  data: {
    foo: "bar";
  }
};
</script>

We should write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      foo: "bar"
    };
  }
};
</script>

No Side Effects in Computed Properties

We shouldn’t have side effects inside computed property functions.

It makes the code hard to understand and unpredictable.

For instance, instead of writing:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  computed: {
    foo() {
      window.foo = `foo ${this.baz}`;
      return `foo ${this.baz}`;
    }
  },
  data() {
    return {
      baz: "bar"
    };
  }
};
</script>

We should write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App",
  computed: {
    foo() {
      return `foo ${this.baz}`;
    }
  },
  data() {
    return {
      baz: "bar"
    };
  }
};
</script>

All we do is return something based on the fields in data .

No key Attribute in template

The template element shouldn’t have the key attribute.

For instance, instead of writing:

<template key='app'>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App"
};
</script>

We write:

<template>
  <div id="app"></div>
</template>
<script>
export default {
  name: "App"
};
</script>

No Mustache in textarea

We should never put a mustache expression between the textarea tags.

Instead, we should use the v-model directive.

This way, get a 2-way binding between our model field and the input value.

For instance, instead of writing:

<template >
  <div id="app">
    <textarea>{{ message }}</textarea>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      message: "foo"
    };
  }
};
</script>

We should write:

<template >
  <div id="app">
    <textarea v-model="message">{</textarea>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      message: "foo"
    };
  }
};
</script>

Conclusion

There are many ways to make mistakes when writing Vue apps.

We should never commit side effects in computed properties.

Also, our component should never expose its state to the outside.

Reserved keys should also never be keys of anything in our component object.

We should use v-model with textarea elements to get a 2-way binding between our model field and the input value.