// 15 Essential Vue.js Interview Questions
Vue.js is one of the most popular JavaScript frameworks for frontend development. It is a top choice for developers who wish to make optimized web pages with a smooth and reactive user experience.
Now, there are lots of great jobs for Vue.js developers, but getting the best work will need you to be well prepared for interviews. Worry not, we’ve got you covered!
In this article, we’ve carefully crafted Vue.js interview questions that will help you ace your interviews. Not just that, even if you aren’t preparing for interviews, these questions & responses will help you explore some interesting new aspects of Vue.js.
So read on!
Looking for Freelance Vue.js Developers? Build your product with Flexiple's top-quality talent.
Hire a Vue.js DeveloperHire NowLifecycle hooks allow users to run a specific code at any point during a component's initialization. As a result, they give users better control over the component and the overall working of the application.
With lifecycle hooks, users can update any data or make relevant API calls at any point during the component's lifecycle, hence the name. For example, the beforeMount hook gets called right before the render function is called for the first time, the template has been compiled, and the mounting has not begun yet.
Now, let's take the mounted lifecycle hook as an example. It is called once the instance has mounted onto the DOM. The user has access to the rendered DOM, template, and the reactive component within the hook.
A common use of mounted is to modify the DOM. In the code given below, we show a message once the components and all its child components have been mounted.
<script>
export default {
data() {
return {
message: "Component has fully mounted",
};
},
mounted() {
this.$nextTick(function () {
this.testMessageFunc();
});
},
methods: {
testMessageFunc() {
console.log(this.message);
},
}
};
</script>;
Now, let’s quickly touch upon a real-life example for the mounted lifecycle hook. Suppose you have a blog application.
When you add a new blog, it would mean a new component will be added to the DOM. As soon as a user creates and publishes the blog, you want to print a message to the frontend.
Using mounted, you can ensure that the message only displays once the blog has become a part of the DOM.
Vue.js advises users to avoid encapsulating too much logic involving reactive data in their templates. Instead, users can define and store computed properties within the objects whose data is involved in the computations.
Saving such computations encourages more uncomplicated code readability and reusability.
One of the main highlights is that the results are cached based on the reactive dependencies involved. In other words, the computation is only carried out when any of the dependencies change and not every time it is invoked.
Such aspects put computed properties at an advantage over methods for the same scenario. After all, calling the specific method would mean the computation happens every time.
For example, consider an object like the one shown below. The object consists of data about an auto manufacturer and the different models they produce.
export default {
data() {
return {
manufacturer: {
name: 'Suzuki',
car_models: [
'Swift',
'Vitara',
'WagonR'
]
}
}
}
}
One can include the following computation in the template if one wants to know about the availability of different car models they make.
<p>Has available models:</p>
<span>{{ manufacturer.car_models.length > 0 ? 'Yes' : 'No' }}</span>
However, the refactored code using computed properties looks as follows. As a result, the code is cleaner, easier to understand, and less computationally intensive.
export default {
data() {
return {
manufacturer: {
name: 'Suzuki',
car_models: [
'Swift',
'Vitara',
'WagonR'
]
}
}
},
computed: {
// a computed getter
availableCarsMessage() {
// `this` points to the component instance
return manufacturer.car_models.length > 0 ? 'Yes' : 'No'
}
}
}
<p>Has available models:</p>
<span>{{ availableCarsMessage }}</span>
Note: Commonly asked Vue.js interview questionBoth composables and components are very fundamental to creating any Vue application. However, both are very different concepts and can be used alongside each other.
Components are the building blocks of a Vue application. Each component encapsulates both rendering and working logic in an instance. In addition, components can have child components that inherit data and traits from parent components.
Composables are functions that a user can create using the Composition API and share for use within different components. Their primary use is to make a piece of code reusable, especially if it is stateful logic.
Through composables, users can take a component's logic and make a function out of it that can be used by other components, even if they don't necessarily have the same kind of state. Additionally, you can create a composable function out of other composables to just simplify the logic.
As an example, check the following code that uses the Composable API for mouse tracking.
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
</script>
<template>Mouse position is at: {{ x }}, {{ y }}</template>
We can divide this code and create composables out of this code for use among different components in the following way.
import { ref, onMounted, onUnmounted } from 'vue'
function eventListener(target, event, callback) {
onMounted(() => target.addEventListener(event, callback))
onUnmounted(() => target.removeEventListener(event, callback))
}
export function trackMouseLocation() {
const x = ref(0)
const y = ref(0)
eventListener(window, 'mousemove', (event) => {
x.value = event.pageX
y.value = event.pageY
})
return { x, y }
}
Now, if we wish to use this composable in a component, we can do so in the following manner.
<script setup>
import { trackMouseLocation } from './mouse.js'
const { x, y } = trackMouseLocation()
</script>
<template>Mouse location is: {{ x }}, {{ y }}</template>
Note: Commonly asked Vue.js interview questionVue.js enables you to validate a component's props primarily in the following ways:
Type Checking: You can check that your props are of a particular data type, like an object, boolean, array, function, or number. You can also put a required field to establish it as a necessary field and a default field to pass a fixed value if the prop isn't provided.
In the example below, we ensure that the testNumberProp attribute type is a numeric value.
<script>
export default {
props: {
testNumberProp: {
type: Number
}
}
}
</script>
Function Instance Checking: You can validate if your prop is an instance of a function. Users can pass constructor functions for such validation, and Vue will check if the prop satisfies this condition or not.
<script>
function testFunc(stringOne, stringTwo) {
this.firstString = stringOne
this.secondString = stringTwo
}
export default {
props: {
testProp: testFunc
}
};
</script>
Custom Validation: You can add customized prop validation by writing a function that takes a property value and returns true or false appropriately. Given below is an example of custom prop validation.
props: {
inputString: {
type: String,
validator: value => {
// Validates the string contains 'web development'
return value.indexOf('web development') !== -1
}
}
}
Vue.js composables and React Hooks have similar working philosophies. However, there are some key differences between the two.
1) Changes in dependencies
React HooksReact Hooks require a dependencies array containing all the component variables it uses to ensure up-to-date data. However, if you don’t pass the proper dependencies, it will lead to inaccurate results, and you have to rely on ESLint to ensure that the dependencies are correct.
Vue.js ComposablesOn the other hand, Vue.js has a reactive runtime system that automatically gathers reactive dependencies.
2) Updates to child components
React HooksAnother difference is that child components can experience updates if event handlers are passed in React. This is avoided by requiring useCallback explicitly.
Vue.js ComposablesHowever, Vue.js doesn't require you to manually cache callback functions. It ensures that child components are updated only when needed, thanks to its reactivity system.
Vue.js’ syntax allows users to put HTML within their templates. As a result, it enables more control and versatility within a Vue application.
Users can inject raw HTML data within their code using the v-html attribute. It enables a piece of text to be interpreted as HTML and processed accordingly. The example below shows the difference between regular Vue text interpolation and v-html.
<p>Using text interpolation: {{ htmlCode }}</p>
<p>Using v-html directive: /<span v-html="htmlCode">/</span></p>
Now, if you wish to incorporate data bindings within HTML attributes, you can use the v-bind directive, as shown below.
<div v-bind:authenticated="authenticatedStatus"></div>
Such attributes are called directives since they instruct Vue to process something in a specific way.
Note: Commonly asked Vue.js interview questionDuplicate code is one of the biggest challenges when extensively testing a web application. One of the primary traits of a well designed application is that the code is modular and reusable. This helps improve readability and avoid redundancy.
With factory factions, you can organize the tests for your Vue.js applications and avoid code duplication.
Additionally, it helps improve code readability and structure. You also get to establish a pattern to follow within your test files so other contributors can pick up and continue creating tests that suit the pattern.
As an example, consider the shallowMount() function below. It gets called repeatedly throughout different parts of the tests and with different options. For example, see how the code snippet below shows each test calling shallowMount() in a very similar manner.
test('calls $bar start on load', () => {
const $bar = {
start: jest.fn(),
finish: () => {}
}
shallowMount(ItemList, {mocks: {$bar}, localVue, store})
expect($bar.start).toHaveBeenCalled()
})
test('calls $bar finish when load successful', async () =>
{
expect.assertions(1)
const $bar = {
start: () => {},
finish: jest.fn()
}
shallowMount(ItemList, {mocks: {$bar}, localVue, store})
await flushPromises()
expect($bar.finish).toHaveBeenCalled()
})
Instead, you could create a factory function involving shallowMount() with specified options to use wherever needed in a specific way. Check the example below.
const shallowMountFactoryFunction = shallowMount ( TestComponent, {
mocks: {
$bar: {
start: jest.fn(),
finish: jest.fn()
}
}
)}
const factoryFunction = shallowMountFactoryFunction()
Now, the logic of shallowMount() is in one place, and you can call it wherever you wish for the function to take effect. Additionally, any changes to this specific calling of shallowMount() can be modified at one place instead of going to different parts of the test and changing at each part.
The Vuex library is a centralized state management library for Vue.js. It enables users to establish a global state for applications with multiple components. This way, all parts of the application can access the state and react while avoiding race conditions, stale data, and complex data passing.
Vuex is established on certain fundamental concepts, each described below:
State: The state is called a store within Vuex, and it is accessible to all the components. Each component can have its own state too. You can create a store within the root component through the createStore() method.
Mutations: Mutations are functions that change the state in Vuex. These are synchronous and take the value as an argument along with the state as the first argument.
Actions: Actions can contain asynchronous transactions, and they commit mutations.
Modules: Vuex offers the ability to divide the store into modules, each with its dedicated store, mutations, and actions.
Filters and mixins are two distinct concepts within the Vue.js framework.
Filters are special text formatting functions that shape the passed data into a particular form. On the other hand, mixins enable you to use reusable code in different parts of the application flexibly.
The following code shows a filter that is defined and then used within the template. This filter capitalizes the first letter of the passed text.
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
The following code shows how to create a mixin and export them for use in other components. The component using the mixin can have other options besides the ones that come with the mixin. Additionally, you can create global mixins.
var testMixin = {
componentCreated: function () {
this.created()
},
methods: {
created: function () {
console.log('mixin used by component!')
}
}
}
var Component = Vue.extend({
mixins: [testMixin]
})
var testComponent = new Component() // => "mixin used by component!"
Note: Commonly asked Vue.js interview questionWatchers are very handy within Vue applications and are an essential part of its reactivity system. You can attach watchers to a component's attributes and define functions that get called when the attribute changes.
In the following example, we defined a test Vue application with watchers defined for its component.
var vm = new Vue({
el: '#demo',
data: {
day: 'Friday',
date: '13th',
dateString: 'Friday 13th'
},
watch: {
day: function (val) {
this.dateString = val + ' ' + this.date
},
date: function (val) {
this.dateString = this.day + ' ' + val
}
}
})
Here, you can see that when the day or date attribute would change, the watcher functions would ensure that dateString updates automatically.
Note: Commonly asked Vue.js interview questionThere is no call to the createStore() that creates a new store instance in this scenario.
Once you add the call to createStore(), Vuex will then update the state stored in this instance through the mutations we define.
Incorporating createStore() would make the code look like the following.
import {
createStore
} from 'vuex'
const testStore = createStore({
state() {
return {
authenticated: false,
user: {}
}
},
getters: {
authenticated(state) {
return state.authenticated
}
},
mutations: {
set_authenticated(state, value) {
state.authenticated = value
}
}
})
We can test that the parent component responds in a particular way using the $emit method within the child component instance.
Post that, we can create a test where we listen for the emitted event from inside the parent component instance. Thankfully, the Vue-test-utils library provides all the relevant functions for this particular test.
The following code is an example of listening for a 'close Modal' event.
import Form from '../Form.vue'
import { shallowMount } from '@vue/test-utils'
describe('Form.vue', () => {
test('form-submitted event emitted when form is submitted', () =>
{
const shallowMountWrapper = shallowMount(Form)
shallowMountWrapper.find('button').trigger('submit')
expect(shallowMountWrapper.emitted('form- submitted')).toHaveLength(1)
})
})
Two-way binding in Vue.js is called so because it updates the other side of the binding as one side changes.
Specifically, it changes the data model if the template changes and vice versa in real-time. This way, it makes user input closely synchronize with the output and makes the application behave reactively.
We can implement two-way binding in Vue.js through the v-model directive. It reacts to the user input event and triggers the change in the template accordingly. A simple example is shown below.
<input type="checkbox" id="audi" value="Audi" v-model="selectedCarModels">
<label for="audi">Audi</label>
<input type="checkbox" id="mercedes" value="Mercedes" v-model="selectedCarModels">
<label for="mercedes">Mercedes</label>
<input type="checkbox" id="nissan" value="Nissan" v-model="selectedCarModels">
<label for="nissan">Nissan</label>
<br>
<span>Selected cars: {{ selectedCarModels }}</span>
new Vue({
el: '#test',
data: {
selectedCarModels: []
}
})
Here, we can bind multiple checkboxes to an array. You can see how Vue.js recognizes the attribute as an array and that it is bound to the checkboxes. Therefore, it adds to the array as you check the boxes.
Slots enable you to compose components around content by reserving space for its insertion.
A slot is specified through
The slot can contain any kind of template code like HTML or other components.
In the following template for a component called
<a
v-bind:href="url"
class="web-link"
>
<slot></slot>
</a>
Now, we can use the component and pass it the link and the webpage name.
<webpage link url="/homepage">
Homepage
</webpage link>
We can create a simple filter for this scenario by using the built-in string method within JavaScript for capitalizing letters.
filters: {
capitalizeAll: function (value) {
return value.toUpperCase()
},
Note: Commonly asked Vue.js interview question