10 tips for building better Vue.js components

1. Components Can Be Loaded Globally or Locally

Vue.js provides two ways to load components — one globally at the Vue instance and the other at the component level. Both methods provide their own benefits.

Loading a component globally makes it accessible from any template within your application including subcomponents. It limits the number of times you have to import your global component into subcomponents. Also if you load components globally you won’t get the Vue register component error “did you register the component correctly?”. Caution, load global components sparingly. It will bloat your application, and even if it is not used, it will still be included in your Webpack builds.

import Vue from 'vue';
import Editor from './componetns/Editor.vue'

//Where 'editor' is the name of the component <editor></editor>
Vue.component('editor', Editor);

Loading components locally provides you with the ability to isolate components and only load them when necessary. When combined with Webpack, you can lazy load components only when they’re used. This makes your initial application file size much smaller and decreases the initial load time.

<template>
  <section>
    <editor></editor>
  </section>
</template>

<script>

import Editor from './Editor'

export default {
  name: 'dashboard',
  components: {
    Editor
  }
}

</script>

2. Lazy Loading / Async Components

Lazy load components using Webpack’s dynamic imports. Vue supports lazy loading of your components at render time and code splitting. These optimizations allow for your component code to be loaded only when it’s needed, decreasing your HTTP request, file size, and automatically gives you performance boosts. The great part about this feature is that it works with both globally loaded and locally loaded components.

Globally loading async components:

import Vue from 'vue';

//Where 'editor' is the name of the component <editor></editor>
//Returns a promise that only gets called when the compoent is rendered and then cached.
Vue.component('editor', () => import('./componetns/Editor.vue'));

Locally loading async components:

<template>
  <section>
    <editor></editor>
  </section>
</template>

<script>

export default {
  name: 'dashboard',
  components: {
    'Editor': () => import('./Editor')
  }
}
</script>

3. Required Props

There are a number of ways to create props for a component; you can pass an array of strings representing prop names, or you can pass in an object with keys as prop names and a configuration object.

Using the object based approach allows you to create a few key configuration changes for individual props, one of which is the required key. The required key expects a true or false value. True will throw an error if the prop is not set when the component is used and false (the default value) will not require or throw an error if the prop is not set. It’s good practice to use the required prop for other developers when sharing components as well as yourself to remind you that a prop is critical for the component.

<template>
  <section>
    <editor v-if="isAdmin"></editor>
  </section>
</template>

<script>

export default {
  name: 'Editor',
  props: {
    enabled: {},
    isAdmin: {
      required: true
    }
  }
}
</script>

4. Trigger Custom Events with $emit

Communication between a child and parent component can be done by using the components built-in function $emit to emit custom events. The $emit function accepts a string for the event name and an optional value to be emitted. To listen for the event, simply add “@eventName” to the component emitting the event and pass in your event handler. This is a great way to keep a single source of truth and have data flow from a child component up to a parent.

<template>
  <section>
    <button @click="onClick">Save</button>
  </section>
</template>

<script>
export const SAVE_EVENT = 'save';
export default {
  name: 'triggerEvent',
  methods: {
    onClick() { 
      this.$emit(SAVE_EVENT);
    }
  }
}
</script>

<template>
  <section>
  <p v-show="showSaveMsg">Thanks for Listening for the saved event</p>
  <trigger-event @save="onSave"></trigger-event>
  </section>
</template>

<script>
export default {
  name: 'TriggerEvent',
  data(){
    return {
      showSaveMsg: false
    }
  },
  components:{
    //You can find Trigger Custom Events in VueJs https://gist.github.com/eabelard/36ebdc8367bfeff75387cc863c810f65 
    TriggerEvent: () => import('./TriggerEvent')
  },
  methods: {
    onSave() { 
        this.showSaveMsg = true;
    }
  }
}
</script>

5. Breakup Components Into Logical Pieces

Easier said than done, but how do you define a logical piece to break a component up into? The first way to break up your component is based on the data change rate. If data is consistently changing in one section of the component, but not in others It should probably be its own component.

The reason for that is if your data/HTML is consistently changing in one section of your template the whole thing needs to be checked and updated. However, if that same HTML is put into its own component with data passed in using props then just that component will be updated when its props change.

Another way to break up your components logically is for reusability. If you have HTML, graphics, or functionality that is used consistently throughout your application like a button, checkbox, logo animation, a call to action or a graphic that has simple changes text — that would be good candidate isolation into a new component that can be reused. Reusable components have a hidden benefit of easier maintenance because you’re changing one component as opposed to having to find a replace and change multiple areas within your code base.

6. Validate Your Props

Instead of using an array of strings to define your props use the object notation which allows for configuring each prop. Two very useful configuration styles are “type” and validator.

Using the type parameter, Vue will automatically type check your prop value. For example, if we are expecting a Number prop but received a String, you would get a warning in the console similar to this:

[Vue warn]: Invalid prop: type check failed for prop “count”. Expected Number

For more complicated validations we can pass a function to the validator property which accepts the value as an argument and returns either true or false. This is very powerful because it allows us to write custom validation against the value that is being passed to that particular property.

<template>
  <section class="custom-validation" :class="[{enabled}, status]">
    <p>You {{status}} the test</p>
  </section>
</template>

<script>
export default {
  name: "CustomValidation",
  props: {
    enabled: Boolean,
    status: {
      default: "fail",
      validator: function(value) {
        return ["pass", "fail"].includes(value);
      }
    }
  }
};
</script>
<style scoped>
.custom-validation {
  opacity: 0.5;
}
.enabled {
  opacity: 1;
}
.pass {
  color: green;
}
.fail {
  color: red;
}
</style>

7. Multiple Props Binding and Overwriting

If your component has a number of props, say 5, 6, 7 or more, it may become tedious to continually set the bindings for each prop. Luckily there’s a quick way to set the binding for all the properties on a component, and that’s by binding an object instead of just a single property using v-bind.

An added benefit of using an object binding is you can overwrite any binding from an object. In our case, if we have isActive set to false in our person object, we can then do another binding on the actual person component and set isActive to true no overwrite the original.

<template>
  <div id="app">
    <person v-bind="person" :isActive="true"/>
  </div>
</template>

<script>
import Person from "./components/Person.vue";
export default {
  name: "App",
  components: { Person },
  data() {
    return {
      person: {
        firstName: "Jaxson",
        lastName: "Pierre",
        dob: "05/22/1996",
        isActive: false
      }
    };
  }
};
</script>

8. Modifying Props in Components

In some instances, you may want to modify the value passed in from a prop. However, doing so will give you a warning “Avoid mutating a prop directly” and with good reason. Instead, use the prop value as the default value for a local data property. Doing so will you give the ability to see the original value but modifying the local data won’t change the prop value.

There is a trade-off. Using this method your local data property is not reactive to the prop value, so any changes to the prop value from the parent component won’t update your local value. But that’s ok if you do need those updates you can combine values using a computed property.

<template>
  <main>
    <section>
      <h2>Non Reactive</h2>
      <p>{{ localFirstName }}</p>
      <button @click.prevent="changeLocalFirstName">Update First Name</button>
    </section>
    <section>
      <h2>Reactive List</h2>
      <ol>
        <li v-for="item in itemsList" :key="item">{{ item }}</li>
      </ol>
    </section>
  </main>
</template>

<script>
export default {
  name: "FullName",
  props: {
    firstName: {
      type: String,
      default: "Mike"
    },
    title: {
      type: String,
      default: "Senior"
    },
    items: {
      type: Array,
      default() {
        return ["lemons", "oranges"];
      }
    }
  },
  computed: {
    itemsList() {
      return [...this.items, ...this.localItems];
    }
  },
  data() {
    return {
      localItems: ["mangos", "apples"],
      localFirstName: this.firstName
    };
  },
  methods: {
    changeLocalFirstName() {
      this.localFirstName = "Jackson";
    }
  }
};
</script>

<style scoped>
</style>


9. Test Utils Mount vs Shallow Mount

There are two ways to create and bootstrap components within Vue tests utils. One is mount and the other shallow mount; both have their strengths and weaknesses.

The mount technique works very well when you want to do interdependent testing between a component and its subcomponents. Allowing you to test whether or not the parent component correctly interacts with its subcomponents as expected. In contrast, as the name implies, the shallow mount technique instantiates and renders just the parent component in complete isolation disregarding any of its subcomponents.

So which method is better? That’s up to you. The strategies that you choose should depend on your measurable goals. Trying to test a component by itself with complete isolation, the shallow method works well. Need to work on a component that has sub-components that you want to ensure communication then go with the mount option. A great option is to use both of them. You’re not limited to just one so mix and match to fit your testing needs.

10. The Power of Vue-cli

The Vue CLI is a powerful command line interface that allows developers to quickly harness a ton of features that can speed up your workflow.

A feature that I tend to use a lot is running vue serve and passing in a path to a Vue component. What’s great about this is that you can fully develop a component in isolation but also get hot reloading and iterate over the component, until its core functionality is out of the way. No need to temporarily import your new component onto the page to develop.

vue serve ./components/views/GoldenRule

When working on a team you may want to pull out one specific component and share it with others. Which leads to the next feature Vue CLI; the ability to export out a Vue component as a library. When called, Vue will automatically build a single file component, move the CSS into an external CSS file (optional you can also inline it) as well as create UMD and Common .js files for importing into other JS projects.

vue build —-target lib --name goldenRule ./components/views/GoldenRule

#javascript #vue-js #web-development

10 tips for building better Vue.js components
1 Likes225.30 GEEK