Thinking in components with Vue.js

An introduction to Vue components with examples

Introduction

JavaScript technology landscape has changed very rapidly in last few years. When Node.js came out, no one predicted that it will be used to develop backend and desktop applications, however that has changed. And now JavaScript can be used on both front-end and back-end area of applications. That means developers can learn JavaScript and be proficient to develop high quality applications.

I remember using jQuery in my web applications. Just include jQuery and write a script to handle click events and make an Ajax request to get small chunks of data and update DOM elements.

To be honest, that was okay for few pages, but imagine if you have to write more than 40% of front-end application code to fetch data and update DOM. Quite often things get out of hand really fast and it becomes a nightmare to manage bits and pieces of JavaScript code scattered across the application.

Now, with the rise of JavaScript based single page applications (SPA)and server side rendering (SSR), it’s possible to write entire front-end application in JavaScript and neatly manage and maintain the front-end code of the application without any pain.

The JavaScript frameworks such as Angular, React and Vue which allows developers to write their entire front-end application in JavaScript with all bells and whistles such as state management, page routing support and component based architecture etc.

These frameworks require you to re-think your application in terms of components and data-driven approach to make interactive user interfaces.

Therefore, gone are the days when you manually find the Dom element and update it with the data, instead put your data in front and center of your application and let these frameworks handle the mundane tasks like keeping your DOM elements in sync with the data.

These frameworks have been developed with a different philosophies in mind and they have their own learning curves. For example, among all three, Angular has the steepest learning curve and Vue is easiest to learn and get productive. All of them use component based architecture. That means, you can break down your entire front-end application in manageable UI components then use them to build your application.

All in all, component based architecture provides a way to keep your application lean with less or no code duplication that makes the code easy to understand by the development team.

In the following article, we will learn about the History of Vue and its ecosystem including the anatomy of Vue component and an overview of each section with examples.

History of Vue

Vue was created by Evan You, while he was working at google on AngularJS 1.0 apps. He created Vue as a progressive JavaScript framework and an performant alternative to Angular.

In nutshell, the term progressive JavaScript framework means, you can use Vue in your existing web application without any hassle and incrementally use the framework features as you need them. Alternatively, you can build an entire front-end using Vue and other supporting libraries.

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. It consists of an approachable core library that focuses on the view layer only, and an ecosystem of supporting libraries that helps you tackle complexity in large Single-Page Applications. — Ref: Link

During its inception, Vue has picked up the best features of other libraries such as templating syntax, two-way data binding and directives from Angular, virtual DOM implementation from React, all while removing the need to have any complicated setup to get going, hefty learning curve to get productive and less head scratching.

At the core, Vue uses reactive data and smarter dependency tracking to figure out which part of the user interface needs to be updated. And by using virtual DOM diffing technique, Vue efficiently creates a smallest batch of user interface changes to be applied to the DOM and then updates the user interface even before you blink your eye.

Vue has become hugely popular in dev community in recent years. In a true sense, it is evolving on stable foundation with a purpose to become a JavaScript framework of choice.

Recently, its popularity on GitHub (~ 130k stars) and npm registry (~ 900k weekly downloads) has reached to the point where it has surpassed React and Angular by fair margin. It has been used by big companies such as Gitlab, Alibaba, Xiaomi, Adobe, Euronews, Nintendo, Grammarly, Codeship, Behance and many more.

In comparison to React and Angular, where Facebook and Google set the roadmap of their frameworks respectively and are entirely responsible for the development of their framework, Vue is truely a shining gem in open source software (OSS) community without any big corporation setting its agenda.

Being said that, Vue has a core team of very smart individuals, large community of developers and growing support of corporate sponsors who wants to see the framework thrive and more importantly they put their money on David against industry Goliaths.

Vue Ecosystem

Vue has come a long way from where it started to become a full fledged framework.

It has a rich ecosystem of official core libraries, great developer tooling support, a galaxy of third party plugins, developer tutorials and a matured ecosystem of related component frameworks, such as Vuetify, BootstrapVue, Element, Quasar, NativeScript-Vue and many more which you may want to pick and choose based on the needs of your application.

Vue Ecosystem

Some of the core libraries maintained by Vue team are as follows with their definitions.

  1. Vue Router (https://router.vuejs.org/) Vue Router is the official router for Vue.js. It deeply integrates with Vue.js core to make building Single Page Applications with Vue.js a breeze.
  2. Vuex (https://vuex.vuejs.org/) Vuex is a state management pattern + library for Vue.js applications. It serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.
  3. Vue Loader (https://vue-loader.vuejs.org) Vue-loader is a loader for webpack that allows you to author Vue components in a format called Single-File Components (SFCs). The combination of webpack and vue-loader gives you a modern, flexible and extremely powerful front-end workflow for authoring Vue.js applications.
  4. Vue Server Renderer (https://ssr.vuejs.org/) Vue-server-renderer facilitates building of isomorphic or universal JavaScript applications which runs both on server and client side where majority of the application code is shared and reused.
  5. Vue Test Utils (https://vue-test-utils.vuejs.org/) Vue Test Utils is the official unit testing utility library for Vue.js.
  6. Vue Dev-Tools (https://github.com/vuejs/vue-devtools) Browser devtools extension for debugging Vue.js applications.
  7. Vue CLI (https://cli.vuejs.org/) Vue CLI is a full system for rapid Vue.js development. It aims to be the standard tooling baseline for the Vue ecosystem. It ensures the various build tools work smoothly together with sensible defaults so you can focus on writing your app instead of spending days wrangling with configurations.

Anatomy of Vue Component

This section will give you a brief overview of a typical Vue single file component (SFC). At high-level, Vue single file component consists of three sections

  • Template
  • Script
  • Style
A Vue single file component is a self-contained piece of user interface which has its own HTML markup, script for interactivity and styles for presentation.

Let’s look at each briefly.

Template section

Template section is where you put your HTML markup code along with any data variables or computed properties which are defined in script section of the code.

You should watch out if your HTML markup here is getting too long, then it is usually a sign that you are doing too many things and you must consider creating a child component for that additional functionality.

Script section

In script section, you can define any local data, props, computed properties, watchers, methods, Vue lifecycle hooks along with the registration of any child component as needed.

Style section

Finally, the style section allow you to define your component styles to make it presentable using normal CSS or by using Less, SCSS pre-processors etc.

Anatomy of Vue component

Above is the one-pager representation of Anatomy of Vue component and here is the gist of the skeleton component.

Example of a Vue component

In the pen below, the template section of a Vue component shows headingText and leadText data variable inside a div tag. HTML markup for user interface can be very verbose, therefore for the sake of brevity I have kept it lean for you to understand.

Basic vue component

Components

This section allows you to register child components which you use in your template. Since, Vue allows incrementally building of user interface, you can easily create small child components and use them to build a composite user interface.

The following are the ways to define and register a child component in Vue.

  1. If you are including Vue with script tag in an HTML file without any build system or you are using online editors such as codepen.io, jsFiddle, jsbin etc. then you can define and register a child component using the following syntax. This will ensure that your child component is registered globally with Vue and then you can use it anywhere in your HTML.
/* In HTML file */
// Parent component
<div id="app">
<!-- Child component coming right up -->
<app-header></app-header>
</div>
// Child component template
<script id="app-header-template" type="text/template">
<div>
...
</div>
</script>
// In script file 
Vue.component('app-header', {
template: '#app-header-template'
})

// Parent component which will be mounted
// on DOM element with id app

new Vue({
/* The element to mount vue component */
el: "#app"
})

Below is the child component demo, showing how to define and register a child component in Vue.

Using Child Component

2. If you are using Vue CLI to generate your app then you can use the following syntax to define and register your child component. The following syntax will import and register the child component with the parent.

//  Using single file component
// ChildComponent.vue component file created in components folder

<template>
<div>
...
</div>
</template>
<script>
export default {
...
}
</script>
// Inside Parent.vue
<template>
<div id="app">
<AppHeader></AppHeader>
</div>
</template>
<script>
import AppHeader from "@/components/AppHeader"
export default {
components: { AppHeader }
}
</script>

Below is the Vue CLI project demo, showing how to import and register child component.

Using Child Component

Props

This section allows you to define variables which are passed to the child component from the parent. You can define properties in either array or object format.

Array format allows you to define Vue component properties quickly, on the other hand, object format gives you more options to define component properties in more detail.

// Inside the component
// Array format to define component properties

props: ["title", "subtitle"]
// Inside the component
// Object format to define component properties

props: {
title: {
type: String,
default: "Thinking in components"
},
subtitle: {
type: String,
default: "Learning component based design"
}
}

For example, in above code, we are using type key to restrict the type of value that can be passed via the title and subtitle props. You can also provide default value using the default key. There are more options which you can use while defining component properties in object format, such as required and validator. You can refer to Vue api documentation for more details.

Using props to pass data to child component

In above pen, we are passing headingText and leadText data to the child component through the props. We have defined headingText and leadText as props in child component and passing the props as attributes when using child component in HTML.

Notice that we are using :heading-text and :lead-text as custom attributes, where : denotes the data binding and heading-text is the prop variable that our child component expects.

It is important to note that, while passing the props, they need to be defined in kebab-case in the component tag (e.g. heading-text), and then they can be accessed in child component as camel-cased variable (e.g. headingText)

Data

This section allows you to define any local variables to provide initial information to the component, which acts as a local state of the component.

// Inside the component
// Use data variables to define
// initial state of the component
data() {
return {
firstName: 'John',
lastName: 'Doe'
email: 'john.doe@example.com'
}
}

Methods

This section is used to define method or event handler functions. In a below code sample, we are setting up a click event handler for the button and defining handleClick handler in methods section. When user clicks on the button, our handleClick method will be called.

Methods and Event Handler

Computed

This section is used to define virtual functions known as computed properties, which you can use in your methods or in template. By default, output of computed properties are cached by Vue, therefore any calls to computed properties are extremely performant.

In a pen below, we are using betterHeading computed property which returns title in uppercase.

Computed Properties

Now you may think, that we can return uppercase title from a method as well, so why use computed properties? Computed properties take full advantage of Vue’s reactivity system and dependency tracking and their output is cached, where as the output of methods are not cached.

In the pen above, output of betterTitle computed property will be cached by Vue and it will not be re-evaluated unless the value of title data variable is changed.

Vue lifecycle hooks

They are special methods which are available to every Vue component. They allow you to tap into component lifecycle events such as beforeCreated, created, beforeMounted, mounted, beforeUpdated, updated, beforeDestroyed, destroyed.

Vue Component Lifecycle Hooks

In the pen above, we have used almost all Vue component lifecyle hooks. Since, they are called automatically by Vue, we have logged the information in console. Few things to note in this example which are as follows,

  • Data variables can not be accessed in beforeCreate hook.
  • If the component does not have a template or a DOM element then beforeMount, mounted, beforeUpdate, updated hooks will not be called at all.
  • We are updating headingText and leadText variables in mounted lifecycle hook. So that, we can trigger beforeUpdate and updated lifecycle hooks which are called just before Vue updates the DOM and after it updates the DOM respectively.
  • In updated lifecycle hook, we are calling this.$destroy() a special method to destroy the component. That will trigger beforeDestroy and destroyed lifecycle hooks which are called just before Vue destroy the component and after the component is destroyed respectively.

Watch

This section is used to monitor properties, variables or computed properties. There are times when you want to take an action when a value of certain variable is changed. In that case setting up watchers is quite handy.

The pen below is very much a non-trivial example of watchers in Vue. It uses most of the concepts mentioned above.

In the example, we have created a component to create a typewriter effect using Vue core library and Lodash helper library.

Using watchers in vue component

On the left, we have a control panel section that contains a text input control to write your message and a range input control to allow you to increase or decrease the delay in typing. On the right, we have a preview section where our component will display the preview of typewriter effect.

Let’s dive into the code.

We are using Vue directives at few places in our HTML template. Now, we haven’t really talked about directives, but let me give you quick overview of them.

The primary form of code reuse in Vue is through components, however there are times when you may need a low level access to the underlying DOM element and may even want to modify it, that’s when Vue directives comes in the picture.

Vue ships with ready to use directives such as, v-model, v-show, v-cloak, v-if, v-else and v-for. Note that you can also create your own custom directives if needed.

HTML Template

Our component will mount on a div with an id app using the following line of code.

// el takes the DOM element 
// which acts a mounting point of our main Vue component
el: "#app"

Control panel

We have two key elements in Control Panel as seen in HTML section,

a) Text input-box for user to type their message — v-model directive is used to bind the message variable.

<input type="text" v-model="message"/>

b) Range input to control the speed of the animation — again v-model is used to bind the speed variable. In addition, range input type comes with two default attributes, 1) min and 2) max as shown below. Both of these attributes are then bound (using : symbol) with respective data variables, minSpeed and maxSpeed.

<input type="range" 
v-model="speed"
:min="minSpeed"
:max="maxSpeed"/>

You must be thinking why are we using v-model:min:max syntax for data binding. v-model is used where we need two-way data binding with our variable and :min and :max is used for one-way data binding of existing HTML attributes to the variables.

Preview panel

We are using v-show directive to toggle the visibility of h3 HTML tag based on the value of showTypeWriter variable.

<label class="my-3">Preview</label>
<h4 class="display-5"> {{ previewHint }} </h4>
<h3 class="display-5" v-show="showTypewriter" ref="typed"></h3>

We are using a special attribute called ref provided by Vue, which gives us access to the h3 DOM element using the following syntax.

// In HTML
<h3 class="display-5" v-show="showTypewriter" ref="typed"></h3>
// In script
this.$refs.typed.innerText

Script Section

We are using the data section to define the initial state of our component. we have defined few variables with their initial values. For example, message variable have “Thinking in components” as initial value, speed variable is set to 150 milliseconds and minSpeed and maxSpeed variables are used in min and max attributes of range input control. Finally, showTypeWriter variable is used to show and hide our typewriter.

data() {
return {
message: "Thinking in components",
speed: 150,
minSpeed: 100,
maxSpeed: 500,
previewHint: '',
showTypewriter: true
}
}

In our methods section, we have created a method called typer and redraw.

typer method is responsible for animating our text and giving a typewriter effect by splitting our message into individual character symbols and animating the text using setTimeout method.

methods: {
typer(){
const symbols = this.message.split("")
const result = []
const animation = () => setTimeout(tick, this.speed)
      let tick = () => {
const character = symbols.shift()
result.push(character)
this.redraw(result.join(""))
if(symbols.length) animation()
}
...
},
...
}

An inline animation function uses setTimeout methods, which takes tickfunction as its first argument and it redraws the text, character by character. And the second argument is this.speed variable, which is responsible to control the how fast each character is appeared.

methods: {
typer(){
...
this.showTypewriter = true
this.previewHint = ""
this.redraw("")
...
},
redraw(text) {
this.$refs.typed.innerText = text
}
}

We want to show our typewriter preview only when typer function is executing. Therefore, we are updating showTypewriter to true and clearing out previewHint variable and text in a h3 tag using the redraw function.

We are using created and mounted lifecycle hooks in the component. In created hook we are creating a debouncedTyper function and attaching to the component’s instance.

_.debounce is a handy method provided by Lodash library to delay execution of the method by number of milliseconds and in our case it is set to 2000 milliseconds.

created() {
this.debouncedTyper = _.debounce(this.typer, 2000)
},
mounted() {
this.debouncedTyper()
}

debouncedTyper method will allow the pause till user has stopped typing-out the message in input box or stopped tinkering with the speed control.

We are calling the debouncedTyper method in mounted lifecycle hook, so that our animation will start right away as soon as our component is mounted on DOM. At this point component will use the initial data provided and start running without any user intervention.

Now, let’s talk a little bit about our watch section, which will monitor message and speed data variables for any changes.

watch: {
message: function(newMessage, oldMessage) {
this.previewHint = "Waiting for you to stop typing.."
this.showTypewriter = false
this.debouncedTyper()
},
...
}

As soon as user start typing in input box, our watch function for message variable will kick in and update previewHint variable, set showTypewriter variable to false and call our debouncedTyper method. The method has 2000 milliseconds delay, therefore, if method is called multiple times then it will wait for 2000 milliseconds before running again.

watch: {
...
speed: function(newSpeed, oldSpeed) {
this.previewHint = "Waiting for you to stop tinkering with speed control.."
this.showTypewriter = false
this.debouncedTyper()
}
}

We are using the same logic in watcher function associated with speed variable. Only at this time we are setting up a different previewHint.

While most of the tasks can be done through computed properties and methods, as they are used quite often in designing interactive user interfaces. However, there are times when you immediately need to know whether the value of the variable has changed. And that’s when you should use watchers.

Vue provides so many options to get the job done and using them appropriately is the key to create apps of exceptional quality. Always remember, as uncle Ben says ,with great power comes great responsibility.

Conclusion

Building interactive user interfaces with Vue is lot of fun. It requires very little to no setup at all!! It is beginner friendly enough to get you started in no time and yet sophisticated, extensible and capable enough to let you build world class apps.

Vue has an extensive documentation on how to use different features of the framework and the core team members are doing an excellent job in evolving the framework and wrote detailed guides for advanced use cases as well.

In this article, we have barely touched the surface on component based design, however, I hope you had a good overview of different parts of Vue component. In coming articles, we will start exploring component based design in more details with advanced examples.


Thank you so much for reading, if you have made it till here. Watch out for my upcoming articles on Thinking in Vue Component.