Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use cases for vue.js directive vs component?

Tags:

When should I use a directive vs a component in vue.js? I'm implementing some stuff from Bootstrap and it looks like I could do it either way (I'm starting with the dropdown menu).

I get the feeling that a directive is more for manipulating the dom on a single element, while components are for packaging a bunch of data and/or dom manipulation. Is this a good way to look at it?

like image 566
Jehan Avatar asked May 22 '14 18:05

Jehan


People also ask

Why we use components in VueJS?

One important feature of Vue is the ability to use components. Components are reusable Vue instances with custom HTML elements. Components can be reused as many times as you want or used in another component, making it a child component. Data, computed, watch, and methods can be used in a Vue component.

What are directives in VueJS?

Directives are instruction for VueJS to do things in a certain way. We have already seen directives such as v-if, v-show, v-else, v-for, v-bind , v-model, v-on, etc. In this chapter, we will take a look at custom directives. We will create global directives similar to how we did for components.

Why VueJS is better than react?

What is the difference between ReactJS and VueJS? VueJS is two-way binding; whereas ReactJS is one-way binding and that's why VueJs uses more computer resources than ReactJS. Moreover, looking at the learning curve, Vue is easier than React and applications can get developed in a shorter time duration than ReactJS.


1 Answers

This Stack Overflow question is the #1 result to the Google query "vue directive vs component". Saurshaz’s answer is currently the accepted one and it’s very wrong in Vue 2.0. I imagine this is leading a lot of people astray so I'm going to weigh in here.

The answer to “should I use a directive or a component in Vue” is almost always a component.

Do you want to have reusable HTML? I.e. reusable widgets? Then use a component. Do you want two of these widgets to have discrete data? Then use a component. The data of one will NOT override the data of another. Maybe that was true in Vue 1.0, I don't know. But it's absolutely not true in Vue 2.0. In Vue 2.0, your components have a data function that returns a unique set of data. Consider this real-life of a Vue dropdown that has an HTML markup similar to the UI Bootstrap dropdown:

<template>   <span class="dropdown sm-dropdown" @click="toggle" :class="{'open': isOpen}">     <a class="dropdown-toggle">       <span class="special-field">{{ label }}</span>     </a>     <ul class="dropdown-menu">       <li v-for="choice in choices">         <a @click.prevent="click(choice)">{{ choice.label }}</a>       </li>     </ul>   </span> </template>  <script>   export default {     name: 'Dropdown',     props: ['label', 'options', 'onChange'],     data() {       return {         choices: this.options,         isOpen: false       }     },     methods: {       click(option) {         this.onChange(option);       },       toggle() {         this.isOpen = !this.isOpen;       }     }   } </script> 

Now in a parent component, I can do something like this:

<template>       <div class="container">     <dropdown       label="-- Select --"       :options="ratingChoices"       :onChange="toggleChoice"     >     </dropdown>      <dropdown       label="-- Select --"       :options="ratingChoices"       :onChange="toggleChoice"     >     </dropdown>   </div> </template>  <script>   import Dropdown from '../dropdown/dropdown.component.vue';    export default {     name: 'main-directive',     components: { Dropdown },     methods: {       toggleChoice(newChoice) {         // Save this state to a store, e.g. Vuex       }     },     computed: {       ratingChoices() {         return [{           value: true,           label: 'Yes'         }, {           value: false,           label: 'No'         }]       }     }   } </script> 

There's a decent amount of code here. What's happening is we're setting up a parent component and inside that parent component we have two dropdowns. In other words, the dropdown component is being called twice. The point I'm trying to make in showing this code is this: when you click on the dropdown, the isOpen for that dropdown changes for that directive and for that directive only. Clicking on one of the dropdowns does not affect the other dropdown in any way.

Don't choose between components or directives based on whether or not you're wanting discrete data. Components allow for discrete data.

So when would you want to choose a directive in Vue?

Here are a couple of guidelines that'll hopefully get you thinking in the right direction.

  • You want to choose a directive when you're wanting to extend the functionality of HTML components and you suspect that you’re going to need this extendability across multiple components and you don't want your DOM to get deeper as a result. To understand what I mean by this, let's look at the directives that Vue provides out of the box. Take its v-for directive for instance. It allows you to loop through a collection. That's very useful and you need to be able to do that in any component you want, and you don't want the DOM to get any deeper. That's a good example of when a directive is the better choice.[1]
  • You want to choose a directive when you want a single HTML tag to have multiple functionality. For example, an element that both triggers an Ajax request and that has a custom tooltip. Assuming you want tooltips on elements other than Ajax-triggering elements, it makes sense to split these up into two different things. In this example I would make the tooltip a directive and the Ajax feature driven by a component so I could take advantage of the built-in @click directive that’s available in components.

1A footnote for the more curious. In theory v-for could have been made as a component, but doing so would have required a deeper-than-necessary DOM every time you wanted to use v-for as well as a more awkward syntax. If Vue had chosen to make a component out of it, instead of this:

<a v-for="link in links" :href="link.href">link.anchor</a> 

The syntax would have had to have been this:

<v-for items="link in links">   <a :href="link.href">link.anchor</a> </v-for> 

Not only is this clumsy, but since the component code would have needed to implement the <slot></slot> syntax in order to get the innerHTML, and since slots cannot be immediate children of a <template> declaration (since there's no guarantee that slot markup has a single node of entry at its top level), this means there would have to be a surrounding top-level element in the component definition for v-for. Hence the DOM would get deeper than necessary. Directive was unequivocally the right choice here.

like image 81
Martyn Chamberlin Avatar answered Oct 24 '22 11:10

Martyn Chamberlin