As of
Est. 

Reactive Components with Vue

What I like about Vue and a quick glance under the hood.

My first experience with HTML goes back to the 90s, and as a compiler guy I was always interested in auto-generating websites. Even then, HTML was a cross-platform alternative to many OS-specific, non-web GUI-frameworks. From then on, many companies preferred web applications over non-web approaches — not only for their customer-facing applications, but also for internal software. Today, I definitely don't want to tinker with SwiftUI, GTK, QT or JavaFX, but with HTML.

The last few decades of my journey as a software engineer have taken me far away from frontend technologies. By the time I got back into frontends, Struts and JSF were gone 👍 and I could choose between Angular, React, Vue and Svelte (and a zillion others).

Angular?VueReactSvelte
What framework should I start with?

Selecting a Web Technology

I knew I wanted to work with HTML 5 & CSS 3. Since I'm aiming for a cross-platform UI, there seem to be few viable alternatives. I looked at Flutter, but I didn't want to learn Dart at the moment. Later, I'd like to take a closer look at Quasar / Electron. This may have also led to some bias towards Vue.

Why Vue?

I had to focus on some technology for a start. The choice between the four alternatives mentioned in was not really difficult in 2022.

The big two, Angular (Google) and React (Facebook), seemed a little dusty and bulky to me. React is a good choice for a commercial venture or client project. Angular, in particular, was said to have a steep learning curve and to annoy developers with incompatible changes. Svelte and Vue had the reputation of being lively, independent challengers, with Vue being more widely used and mature than Svelte at the time.

Vue 3

When I wrote my first Vue examples, the current version was still version 2. Vue 3 was on the horizon. With the major version switch from 2 to 3, everything felt new and fresh. No more vue-cli, which tended to install lots of node packages with vulnerabilities. Vue 3 comes with automatic support of the composition API. With Vite came a slick server that supports HMR really fast. Rollup + esbuild replaced Webpack. In VS Code, Volar replaced Vetur. Everything felt sound and efficient.

What it's like?

The main contributions of Vue are:

Reusable Components

Like most frontend frameworks, Vue helps break up web pages into components: Smaller, simpler parts that are easier to implement, reuse, and maintain. Components can themselves be decomposed into smaller components.

NavBarTopicsHelp               Main                     SearchFieldSearchResultListPreviousNext
Decomposing a frontend with components

Vue lets you define components that combine presentation (HTML), state & logic (JavaScript) and styling (CSS) into a single definition. Components can receive parameters (called properties). These are set by the parent that uses the component. Thus, there is a data flow through properties from the parent to the child. The reverse direction is implemented by events: The component emits an event and the parent respond to it.

There can be multiple instances of the same component, each with its own properties and internal state. Additional external state can easily be provided by modules or by libraries like Pinia. The fun begins when Vue automatically reacts to state changes, see the section on Reactive Rendering below.

Vue components have a lifecycle. The lifecycle for Vue's composition API is shown in the figure below.[1] Once created, components are A) rendered into the DOM of the web browser. Whenever Vue detects the need for an update, the component is B) re-rendered and the existing DOM is adjusted accordingly. At the end of its life, the component is C) removed from the DOM again. Like React, Vue also uses a virtual DOM for performance reasons. It is the digital twin 🙂 of the DOM that can be updated cheaply and often without incurring re-layout and visual rendering costs until all changes stabilized.

setuponBeforeMountA) InitialRenderonMountedmountedonBeforeUpdateonBeforeUnmountB) Re-render/ PatchonUpdatedC) Removefrom DOMonUnmounted
Vue 3 lifecycle hooks for composition API.
Boxes are hooks, ellipses are Vue actions.

For each of these three actions, there are before- and after-hooks that Vue automatically invokes if the component defines them,[2] allowing for fine-grained configuration, dynamic actions or better debugging.

HTML Templating

The presentation of a Vue component looks very much like a normal HTML fragment. Other Vue components can be used like normal HTML elements. For templating, Vue defines some specific directives that all start with v-. v-if is for conditional rendering. v-for iterates over lists. v-bind:<name> – or :<name> for short – binds an attribute to a JavaScript expression. {­{ and }} containing JavaScript expressions are replaced by the result of evaluating that expression.

vue
<template>
 ... HTML elements go here
 <p v-if="show">....</p>
 <OtherVueComponent :prop="some expr">
  <ol>
   <li v-for="entry in entries" 
    :key="entry.id">
    <a :href="entry.url" class="font-sans">
     {{ entry.heading }}
    </a>
    <div>{{ section.body }}</div>
  </li>
 </OtherVueComponent>
</template>
<template>
 ... HTML elements go here
 <p v-if="show">....</p>
 <OtherVueComponent :prop="some expr">
  <ol>
   <li v-for="entry in entries" 
    :key="entry.id">
    <a :href="entry.url" class="font-sans">
     {{ entry.heading }}
    </a>
    <div>{{ section.body }}</div>
  </li>
 </OtherVueComponent>
</template>

If you are used to HTML, Vue templating looks familiar. It also provides powerful mechanisms like slots and fall-trough attributes.

If you know Vue, I won't bore you with more details. If you don't know it, I won't try to teach you Vue in a nutshell. If I've piqued your interest, visit vuejs.org.

Reactive Rendering

Vue monitors the state of the web application and is optimized to render in a timely manner only those parts of the GUI that need to be adjusted based on state changes.

So at its core, Vue is a library for managing application state and the effects on the DOM resulting from state changes. It implements a dataflow graph for the dependencies. Sources of this graph are the single state variables and the sinks of the graph are uses of values in templates and render functions.

When part of the state changes, Vue can determine which part of the rendered page is directly or indirectly affected by that change. In the example graph below, a change of a only affects the rendering of x, but a change in b makes it necessary to redraw x and y.

axby
Mini example: dependency graph

Of course, the graphs of real applications are much larger and have more intermediate layers. The nodes can also be complex functions. If their inputs do not change, Vue will not recompute them, but reuse the previous cached result. Vue calls them computed properties.

So as a programmer, you have to tell Vue what part of the state you want Vue to observe and what is affected by state changes and should be recomputed or redrawn. Vue does a good job of figuring out some of these things itself. For example, the use of JavaScript in templates is an unmistakable sign that this part of the template needs to be re-rendered when the value of the expression changes.

TypeScript & IDE Support

The script part of a Vue component can be written in JavaScript, but also in TypeScript. Personally, I prefer TypeScript because it protects me from many stupid programming mistakes. Especially when accessing the reactive state of Vue, it is very helpful to be warned in the IDE, for example if you forget to dereference .value of ref()s.

A fool with a tool is still a fool. Which IDE you use doesn't matter much. For Vue, VS Code has pretty good support and so I use VS Code as my IDE. Vue support is provided by the Volar plugin. Although I still miss some of the refactorings I was used to from IntelliJ Idea, VS Code + Volar is a smooth and effective combination.

Advanced Topics

Hydration

Normally, hydration (explained in a minute) goes completely unnoticed. At least as long as there are no errors. Hydration is a feature of Vue that plays an important role in SSR, and therefore also for our Static Site Generation. When Vue components are rendered on the server, the result is a static HTML page with a single script. The HTML can be quickly displayed in the browser. Later, the included script adds all the interactive features.

In fact, it regenerates most of the page again on the client side. Turning the static HTML into an lively, reactive version is called hydration. It is similar to putting on a sweater: Hydration has some assumptions about how the page looks before it is covered. If those expectations are not met, hydration fails badly. The visual result is usually irritating and disturbing.

I had trouble with hydration issues once in a while. The first time when I was learning about Teleports. The other time when I got strange errors whenever I rebuilt the site.


  1. Vue's original API, the Options API, has slightly different hooks. ↩︎

  2. These hooks are only called when the component is rendered in a browser. They are not called during server side rendering (SSR). ↩︎