Vue.js Interview Questions

Prepare better with the best interview questions and answers, and walk away with top interview tips. These interview questions and answers will boost your core interview skills and help you perform better. Be smarter with every interview.

  • 4.8 Rating
  • 40 Question(s)
  • 40 Mins of Read
  • 9654 Reader(s)

Advanced

When rendering a list of items, the key attribute allows Vue to keep a track of individual Vnodes. The key value must be unique as it acts as an identity.

If the key attribute is NOT used and if the contents of the list change (such as sorting a list), the Virtual DOM, instead of moving elements up or down, prefers to patch the nodes in place with the updated data to reflect the change. This is the default mode and is efficient. 

When a unique key value IS provided, the elements will be reordered based on the change to the keys (and not patched in place with new data) and if keys are removed (such as when items in a list are deleted), then the corresponding nodes are destroyed or removed as well. 

Note the diagram below:

 

 

Here, we have a parent component rendering a list of child components. We see three list items being rendered as three child component nodes. Each of these child components contains a span tag and an input box and possibly a local state object (optional). Let’s examine two scenarios now: 

When NOT using the key attribute: If the list is re-sorted for instance, Vue will simply patch the already present three nodes with the re-sorted data, instead of moving the nodes. This will work fine as long as the user has not typed in/changed the local state of one or more of these child components. So, let’s say a user has typed in component no. 3’s input box. When the list is re-sorted, the span tag’s content for component no. 3 will change however the input box will remain there with the user typed content/stateful data. This is because there is no way for Vue to identify component no. 3 and it simply repatches what it sees as updated data i.e. the contents of the span tag.

When the key attribute IS used on the child component, Vue knows the identity of the component and when the list is re-sorted, the nodes will be moved instead of being re-patched. This will ensure the manually edited input box travels to its new position along with the entire component.

The key attribute can also be used when conditionally rendering components/elements to signal Vue about the uniqueness of elements and to ensure elements are not re-patched with new data.

The typical way to output content in a template is using the mustache syntax tags to output data from a method, prop or data variable. The mustache tags however render text. If you try to render HTML using mustache tags, it will render as a text string and won’t be parsed. To render & parse content as html, we can use the v-html directive as demonstrated below. 

Template

<div id="app" v-html=”title”></div>

App

new Vue({
    el: '#app',
    data: {
      title: '<h1 style="color: green;">Vue.js</h1>'
    }
});

Output

Vue.js

As shown in the example above, the v-html directive parses any HTML and as a result, the statement above is rendered as desired. v-html should not be used unless the developer understands risks associated with it. When incorrectly or carelessly used, v-html can expose the site/app to injection attacks where malicious code may be injected and executed from external sources. When interviewing the candidate, please ensure the candidate is aware of this issue with v-html.

Vue-loader is a loader module for webpack that allows us to write single file components using the .vue file format. A single file component file has three sections namely template, script and style. The vue-loader module allows webpack to extract and process each section using separate loader modules such as the SASS or SCSS loaders. The setup thus allows us to seamlessly author apps using .vue files.

The vue-loader module also allows static assets to be treated as module dependencies and enables processing using webpack loaders. And it also allows hot reloading during development.

Mixins allow us to write pluggable and reusable functionalities for Vue components. If you have a set of component options such as lifecycle hooks, methods etc. that you wish to reuse across multiple components, you can write it as a mixin and simply reference it in the component. The contents of the mixin are then merged into the component. If you’re defining any lifecycle hooks in the mixin, then it would get execution precedence over the component’s own hooks.

Let’s say we have a Node.js backend server running on localhost:4040. To ensure it is proxyed in and accessible from the components, we can configure the vue.config.js file and include a devServer section as shown below: 

In the vue.config.js file: 

module.exports: {

devServer: {
proxy: {
‘/api’: { 
target: ‘http://localhost:4040/api’, 
changeOrigin: true 
}
}
}
}

By implementing prop validation options, we can specify type requirements for individual props. This has no implication in production but throws warnings during the development phase, thereby helping the developer identify potential issues with incoming data and the particular type requirements for a prop. 

An example of configuring three props:

props: {
    accountNumber: {
        type: Number,
        required: true
    },
    name: {
        type: String,
        required: true
   },
   favoriteColors: Array
}

The Document Object Model or DOM defines an interface that allows languages such as JavaScript to access and manipulate an HTML document. Elements are represented by nodes in a tree and the interface allows us to manipulate them. This interface, however, comes with a cost and a large number of very frequent DOM operations will slow down the page.  

Vue solves this problem by implementing a virtual representation of the document’s structure in memory where a virtual node (VNode) represents nodes in a DOM tree. When manipulation is needed, instead of performing it on the real DOM, the calculations and operations are performed in memory on the Virtual DOM. This is naturally faster and allows the Virtual DOM algorithm to compute the most optimised way to update the actual DOM structure. 

Once this computed, it is applied to the actual DOM tree. This boosts performance and is the reason why Virtual DOM based frameworks such as Vue and React have gained so prominence. 

A Vue plugin allows developers to build and add global level functionality to Vue. This can be used to add globally accessible methods and properties, assets, options, mixins and other custom API to an application. An example of a Vue plugin is VueFire plugin that adds Firebase specific methods and binding to the entire application. Thereafter firebase functions are available within the ‘this’ context from anywhere in the application structure.

Vue allows us to build templates in a multitude of ways, the most common of which is to just use HTML with special directives and mustache tags for reactive features. You can, however, also build templates using JavaScript using a special class of functions, known as render functions. These functions are close to the compiler which means they’re more efficient and faster than other template types. Since you’re using JavaScript for writing render functions, you can use the language freely to add custom functionality directly wherever needed. 

This is extremely useful for advanced scenarios where standard HTML templates may not be the best option. 

Here’s a Vue app that uses HTML as a template

new Vue({
  el: '#app',
  data: {
    fruits: ['Apples', 'Oranges', 'Kiwi']
  },
  template:
      `<div>
         <h1>Fruit Basket</h1>
         <ol>
           <li v-for="fruit in fruits">{{ fruit }}</li>
         </ol>
      </div>`
});

Here’s the same app made using render functions:

new Vue({
  el: '#app',
  data: {
    fruits: ['Apples', 'Oranges', 'Kiwi']
  },
  render: function(createElement) {
    return createElement('div', [
      createElement('h1', 'Fruit Basket'),
      createElement('ol', this.fruits.map(function(fruit) { 
        return createElement('li', fruit); 
      }))
    ]);
  }
});

Outputs:

Fruit Basket

  1. Apples
  2. Oranges
  3. Kiwi

In the above example, we’re using a function that returns a series of createElement() invocations, each of which is responsible for generating an element. While the v-for directive does the job in the case of HTML based templates, when using render functions we can simply use the standard .map() function to loop over the fruits data Array.

While this depends on the purpose of the component and it’s usage, the created lifecycle hook is generally ideal for placing an API call. At this point, the component’s data and reactivity features are available to operate, however, the component has not rendered yet.

The updated hook is called after reactive data is updated and the virtual DOM is re-rendered. It can be used to perform DOM related operations, however, there is no guarantee (by default) that child components would’ve rendered, though that can be ensured as well by using this.$nextTick inside the updated function.

Arrow functions don’t define a ‘this’ context of their own and are instead bound to their parent function’s context. When you use an arrow function ( => ) in a Vue app, the ‘this’ keyword won’t be bound to the Vue instance and hence will throw errors. Therefore, it is strongly advised to use the standard function declaration instead.

When we dynamically switch components as a result of a data property or some other reactive state, they’re re-rendered everytime they’re toggled in to render. While you may want this behaviour, there are situations where re-rendering may not be suitable. For instance, you may have a component that brings in data from an API call when created. You may not want to place this API call every time this component is dynamically switched in to render. That is when you can enclose the component within the keep-alive element. The keep-alive element caches the component and fetches it from there instead of re-rendering it every time.

When an application grows in size, both in terms of features and codebase, managing state becomes difficult and using an endless network of downstream props and upstream events is certainly not a wise decision. In such a situation, it becomes necessary to offload state management to a central management system. The Vue ecosystem offers Vuex which is the official state management library and also a recommended pattern for storing state centrally. 

Vuex allows maintenance of a central state. Components use Vuex as a reactive data store and update when the state updates. Multiple and non-related components can depend on the same and central state store.

In this case, Vue acts as a pure View layer. To modify the state, the view layer (such as a button or an interactive component) needs to issue a Vuex ‘Action’, which then does the desired task. To update or mutate the state, Vuex offers ‘Mutations’. An action commits a mutation and only then the state updates.

The purpose of this workflow is to leave a trail of operations that can be used/audited.

When a large application uses a lot of components, it may not make sense to load up all components at the same time from the server. In such a case, Vue allows us to define components that are loaded from the server asynchronously, as and when needed. When declaring or registering components, Vue accepts a factory function that offers a Promise. The component can then be ‘resolved’ when called. 

This saves bandwidth and application bootstrap time by loading only the essentials and deferring async components to their invocation time in the future.

Here’s a simple example of how a component can be made asynchronous. 

new Vue({
    components: {
        ‘tweet-box’: () => import(‘./components/async/TweetBox’)
    }
}); 

When used this way, Webpack’s code splitting feature is employed to deliver this functionality.

Beginner

A progressive framework offers very less adoption resistance, making it easier for existing projects (built using other technologies) to adopt and move to a new framework. Vue.js is a progressive framework because you can start by incrementally adopting it into your existing application, instead of rewriting the entire app from scratch. 

The most fundamental and core parts of Vue deal with the ‘view’ layer and hence you can begin your journey by gradually bringing Vue into your app and replacing your ‘view’ implementation with a Vue app. 

Due to its progressive nature, Vue works really well with other libraries and is very easy to get started with. This is in contrast to frameworks like Angular.js which requires an existing application to be completely re-imagined and implemented in the framework.  

Vue.js makes it easy to render data and hides the internal implementation for us. Consider the following example: 

HTML

<div id=”app”></div>

JavaScript

const greeting = “Hello there!”;

const appDiv = document.getElementById(“app”);

appDiv.innerText = greeting;

The above code segment will display the phrase ‘Hello there!’ in a div with the ID ‘app’. The code above contains all the steps needed to achieve the result. We selected the DOM element with the ID ‘app’ first, then we used the innerText property to manually set the contents of the div.

Now, let’s see this as a Vue application.

Template

<div id=”app”>{{ greeting }}</div>

App

new Vue({
    data: {
       greeting: ‘Hello There!’
    },
   el: ‘#app’
});

In this case, we created a data property named ‘greeting’ in a Vue app, but then all we did was type ‘greeting’ using the mustache syntax in the div without worrying or witnessing the internal implementation. We declared the ‘greeting’ data variable and Vue did the rest. This is what declarative rendering looks like. Vue manages the internals and hides it from you. 

To iterate through an Object or an Array, we can use the v-for directive. Here’s an example: 

Template

<div id="app">
    <ul>
      <li v-for="(value, key) in card">{{ key }} - {{ value }}</li>    </ul>
 </div>

App

new Vue({
  el: '#app',
  data: {
    card: {
      name: 'John Doe',
      age: 25,
      city: 'New York',
      country: 'US'
    }
  }
});

Output

  • name - John Doe
  • age - 25
  • city - New York
  • country - US

The above code will output the string ‘<h1 style="color: green;">Vue.js</h1>’ in the div. The reason why this entire tag renders as a string is because the mustache template tags ({{ title }}) treats incoming data as a String and does not parse it as executable code. This also helps mitigate XSS related issues where malicious code is injected into pages. This is akin to using the elementSelector.innerText = text statement in JavaScript.

To implement two-way data-binding, we can use the v-model directive. The v-model directive is largely syntactic sugar over:

<input type="text" :value="nameInput" @keyup="nameInput = $event.target.value">

In the statement above, a data attribute named ‘nameInput’ is being set to the value of the input box whenever a ‘keyup’ event is observed. At the same time, we’re binding the value attribute of the input box to the ‘nameInput’ data property. This way, a two-way data relationship is established between the form field and the data property. 

v-model does this and manages the process more efficiently than this manual setup. To replicate the above effect using v-model here’s the same input box again:

<input type="text" v-model="nameInput">

It is also important to note that when two-way data binding is implemented, the data property used is considered as the source of truth. Any changes done on the data property will take precedence over user input events on the form field.

Click events can be captured by using the v-on:click directive. This directive can also be expressed using the shorthand notation @click. Here’s an example: 

v-on:click notation

<a v-on:click=”clickHandler”>Launch!</a>

@click notation

<a @click=”clickHandler”>Launch!</a>

When a prop is assigned value as a function of binding to an attribute using the v-bind directive, it is referred to as a dynamic prop. For instance, the following component’s ‘tweet’ prop is bound to a data attribute called tweetText. This is opposed to a static hardcoded value. This binding is always one-way which means data can flow down from a parent component to a child and never the other way round. 

<TweetBox :tweet=”tweetText”> 

Directives are family of special attributes that you can add to your template HTML tags to empower them with special reactive capabilities. Directives allow elements in the template to react to changes as per defined logic using data properties, methods, computed/watched properties and inline expressions.  For instance, the following code example uses the v-on directive to implement a click event listener on the component.

<SignUpButton v-on:click=”doSignup” /> 

or

<SignUpButton @click=”doSignup” />

In this example, we’re using the v-if directive to display or remove an element/component based on a data property called showButton. Directives begin with v- to indicate Vue specific attributes. The exception to this rule is the shorthand notations for v-on and v-bind. 

<SignUpButton v-if=”showButton” />

Vue also allows defining our own custom directives. 

The v-show directive allows an element to be conditionally displayed. In the code below, the element would be displayed only if the isDisplayed data attribute is true.

 <TweetBox v-show=”isDisplayed”> 

The visibility of the element is toggled using the ‘display’ CSS property when using the v-show directive.

While both v-show and v-if are used for conditionally displaying elements, the latter offers a true implementation of conditional rendering. v-show simply toggles the ‘display’ CSS property to show or hide an element, whereas the v-if directive creates or destroys components. This is generally more expensive every time the display state changes. 

 The v-show, on the other hand, is less expensive because it simply toggles the element’s CSS display attribute. So, if the element has to be toggled quite often, the v-show offers a better and more optimised result than the v-if. 

 In terms of an element’s initial rendering costs when the app is loaded, v-if will not render the nodes for elements that are hidden initially whereas v-show will render the elements with their ‘display’ CSS attribute set to ‘none’.

We can implement event listeners using the v-on directive on any element. In addition, v-on also allows us to use key modifiers for common keys such as ‘enter’, ‘tab’, ‘esc’, ‘space’ and more. Here’s an example:

Template

<textarea @keyup.enter="storeComment"></textarea>

App

new Vue({
  el: '#app',
  methods: {
    storeComment(event) {
      // access the value of the textarea box using event.target.value or use v-model to bind to a data property
    }
  }
});

Routing in an SPA built with Vue can be implemented using the official vue-router library. This library offers a comprehensive feature set that includes features such as nested routes, route parameters & wildcards, transitions, HTML5 history/hash mode and customized scroll behaviour. Vue also supports certain third party router packages as well.

The best way to call event.preventDefault() on an event listener is to use the .prevent modifier with the v-on directive. Here’s an example: 

<a @click.prevent=”doSomethingWhenClicked”>Do Something</a>

Filters are an incredibly easy way to implement custom text formatting in Vue apps. They’re like operators that can be piped (using the pipe character) in an expression to achieve results. Here’s an example of a filter that reverses the text string:

Template

<div id="app">{{ title | reverseText }}</div>
App
new Vue({
    el: '#app',
    data: {
      title: 'This is a title'
    },
    filters: {
      reverseText(text) {
        return text.split('').reverse().join('');
      }
    }
});

Output

eltit a si sihT

In the above example, we created a filter called reverseText which reverses a text string and returns it. It is a simple function that takes an input and returns a processed output. By declaring it under filters, this becomes a filter that we can use in our templates. 

In our template, we simply piped the reverseText filter to the data variable that we wanted to display within the mustache tags. This way, multiple filters can be piped together. Filters thus provide a very elegant way to process text.

Vue allows us to bind to the class attribute. In the example below, we’re binding the class attribute to an object which allows us to toggle a class using a data property.

Template

<div :class=”{ divStyle : showDiv }”></div>

App

new Vue({
    el: '#app',
    data: {
 showDiv: true
    }
});

In the code above, the class name ‘divStyle’ will be applied to the div as long as the ‘showDiv’ data property is true. 

This can be achieved by using an Array when binding the class. Here’s how this would be achieved:

Template

<Button :class=”[‘btn’, ‘btnRed’, { btnActive : isActive }]”>Process</button>

App

new Vue({
    el: '#app',
    data: {
      isActive: true
    }
});

In the above code segment, the array of individual classes would be concatenated and the expression in the object is evaluated reactively based on the value of the ‘isActive’ data property.

Computed properties are outcomes of a special category of functions which auto-compute when dependent properties change. They are used in place of inline expressions to better express complicated logic which is impractical to incorporate as inline expressions in the template. 

Each computed method is available in the template section as a property. When dependent properties change, the computed method auto-computes and caches the result, which makes it better than using plain methods. Methods will always recompute when accessed, whereas a computed property will not recompute if the properties used within the method have not changed since the last compute and cache phase.

This important thing to note here is that change in dependencies is only considered if the properties used in the method are reactive, such as data properties. 

Here’s a simple example that demonstrates a computed property:

Template

<div id="app">
  <input type="text" v-model="email" :class="{ invalid : isInvalid }">
</div>

App

const emailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/

new Vue({
    el: '#app',
    data: {
      email: ''
    },
    computed: {
      isInvalid() {
        return !emailRegEx.test(this.email);
      }
    }
});

In the above code example, the isValid computed property returns a true if the RegEx test fails for the email input box. If the typed in value is considered invalid by the email validator, then we see the text box as red (You’ll have to create a class called .invalid and set the background color property to red). As the user types in, the computed method re-evaluates and the moment the format is validated, the invalid class is removed dynamically.

This can be achieved by using the scoped attribute on the style tag. Internally Vue uses the PostCSS plugin to assign unique data attributes to all styled elements and the styles are then targeted at these unique elements. As an example,  

<template>
    <div class=”title”>This is a title</div>
</template>
<style scoped>
    .title {
        font-family: sans-serif;
        font-size: 20px;
</style>

Data can be passed down to child components using props which act as one-way inlets in components. Here’s an example: 

<template>
    <div>
      <contact-list-item v-for=”contact in contacts” :contact=”contact” />
   </div>
</template>
<script>
    import ContactListItem from ‘./ContactListItem’;
    export default {
name: ‘address-book’,
data: function() {
return {
contacts: [.....]
}
},
components: {
ContactListItem
}
}
</script>

The bound prop ‘contact’ on the contact-list-item is an inlet that receives data from the parent component where it is being used as a child. Now, within the contact-list-item component:

<template>
    <div>
        <span>{{ contact.name }}</span>
        <span>{{ contact.email }}</span>
   </div>
</template>
 
<script>
    export default {
     name: ‘contact-list-item’,
props: [‘contact’]
    }
</script> 

We’ve declared a prop called ‘contact’ here which brings data in and we can then directly display in the template section as shown.

Components, are essentially Vue instances which encapsulate template, logic and optionally local reactive data properties to deliver a custom built element that can then be reused. Reusability is at the heart of building components.  

When building apps using Single File Components, components are defined in files with .vue extension. Single File Components contain three sections, a template section which defines the HTML layout for the component, a script section that defines the data, props and logic units like methods and exports the contents as a Vue component. There is also a style section which is used to define the stylesheet for the component. Single file components are compiled using module bundlers like Webpack.

Vue instances (components) go through a lifecycle, from the point they’re initialized to the point they’re destroyed and removed. Along the way, there are several stages where Vue allows developers to run custom functions. These functions are called lifecycle hooks. Here’s a list of some lifecycle hooks: 

  • created
  • mounted
  • updated
  • destroyed

Slots allow you to define elements that can encapsulate and accept child DOM elements. The enclosing <slot></slot> elements in a component’s template, serve as outlets for any DOM elements that are captured by enclosing component tags. Here’s an example:

Post.vue | A component that implements slots

<template>
 <div class="hello">
   <h3 class="title">{{title}}</h3>
   <div class="content">
     <slot></slot>
   </div>
 </div>
</template>
 

App.vue | An App component that uses the Post component

<template>
 <div id="app">
   <Post title="Hello from Vue!">

Vue is a progressive framework for building user interfaces. Unlike other monolithic frameworks, Vue is designed from the ground up to be incrementally adoptable. The core library is focused on the view layer only, and is easy to pick up and integrate with other libraries or existing projects. On the other hand, Vue is also perfectly capable of powering sophisticated Single-Page Applications when used in combination with modern tooling and supporting libraries.

   </Post>
 </div>
</template>

In the above example, the text in italics is rendered inside the region marked with the <slot> element in the Post component. 

Watchers allow us to observe specific properties for changes and perform custom actions that are defined as functions. While their use case intersects with that of computed properties, watchers are required sometimes to perform custom actions or run expensive operations when a certain data property changes.

Custom events can be emitted by using this.$emit(‘event-name’, eventPayload). This can then be intercepted on the parent component using the v-on directive, just like any other event.

While this is not a convention, developers often name the root Vue instance using the variable name ‘vm’ which stands for ‘ViewModel’ since Vue is essentially responsible for the view layer and is partly inspired by the MVVM (Model-View-View-Model) pattern. It is however not necessary at all to name a root instance as ‘vm’.

Description

Prepare better with the best interview questions and answers, and walk away with top interview tips. These interview questions and answers will boost your core interview skills and help you perform better. Be smarter with every interview.
Levels