React vs. Vue (2)
Part II - Vue
I was several weeks into React development when I decided to switch to Vue. At that point, I had finished only a part of my application. I was recreating an existing (old) PHP web application containing data input forms, calendars, reports and such. Progress was slow. I didn’t get the productivity from React that I had hoped for. Perhaps it was me. But then again… I had completed several weeks of practical training and I was using React on and off for over 2 years. So I decided to give Vue a try, which was -at the time- completely new to me. As I was in a hurry to get actual work done, I did not spend too much time with technical instructions and training. I read through the official manuals and started recreating the same data forms once again. This time, I was pleasantly surprised.
Conceptually, a Vue component is an object that inherits from the Vue base class. As such, it is “supercharged” with functionality made available via instance methods and properties. This notion takes a bit of getting used to, as there various declarative sections, such as data, methods, computed, etc. which the programmer defines as objects. These comprise the building blocks of a component. For example, internal state goes into the data object, behaviour goes into methods, computed properties go into computed, and listeners that respond to state changes go into watch. The presence of these so-called watchers is interesting, as they provide a mechanism for declarative reactive programming without having to create and maintain data stores and dispatchers. The component accesses all information via the this keyword, which means even though properties, state and behaviour are declared within different scopes, they are all injected into the same instance. Setters and getters are created behind the scenes for reactivity so that rerendering is triggered automatically.
Just as with any other modern UI framework, a Vue application can be visualized as a hierarchy of components. Components are composable and inheritance plays only a minor role in the application design. At the top of this hierarchy are views. Views are complete web pages and although they have a navigable URL, their implementation is exactly the same as that of a regular component. The router is an extra library that needs to be added to Vue, which is again similar to React. Vue provides a plugin mechanism for this purpose. There are many stock plugins, such as UI/widget libraries, authentication, internationalisation, and whatnot. You can also create your own plugins which is quite easy to do. Just ot prove this point, you find a minimal i18n plugin implementation at the end of this article. The router plugin is perhaps the most frequently used in SPA design. With Vue, however, you are not limited to SPAs. You can also create traditional multi page web applications or even server-side rendered (SSR) applications.
We had previously talked about the unidirectional dataflow that underlies React. Vue is based on the same principle. Props are read-only and data always flows from parent to child elements. To that end, the state data of a parent element becomes the prop of a child element and props are implicitly read-only and cannot be modified by its owner. An application will generally follow this design principle to keep things from getting overly complex. However, there is a notable exception, namely input bindings that are based on the v-model construct. You can attach any variable to a v-model and this variable is then allowed to be mutated by the child component. As mentioned, this is mainly used for edit/input components. Effectively, it’s just the same as passing a mutation handler from the parent to the child, but in my opinion it is syntactically cleaner. A great example of knowing when to break the rules for the described use case.
Let’s end this brief introduction of Vue with a code example. It’s the same as in the preceding React article: an extremely simple self-updating clock component. Like its counterpart, it updates every second and displays a tooltip element with the current date on mouseover. The clock is started in the created lifecycle method. The underlying JS timer is properly deallocated when the component is destroyed in the lifecycle method of the same name. There is no need for explicit updates, as the component rerenders automatically when any of the variables inside data changes.
Example: self-updating clock component with local state using Vue lifecycle methods
Example: i18n feature designed as a Vue plugin
let i18nCatalog = new Map()