Skip to content

Instantly share code, notes, and snippets.

@pomle
Last active March 10, 2022 05:56
Show Gist options
  • Save pomle/c3904a39470eadfd6a6fdfbff7608475 to your computer and use it in GitHub Desktop.
Save pomle/c3904a39470eadfd6a6fdfbff7608475 to your computer and use it in GitHub Desktop.
React vs. Vue

React vs. Vue

This text explains why I believe we should allow and prefer the React library for frontend development for client facing applications.

This document tries to be as objective as possible, except under the opinion section. I have not brought up issues that can be solved with lint rules or are already solved with tooling. I have also taken for granted that TypeScript is a given requirement for the organisation long term.

High importance issues

These are issues with Vue that impact robustness and quality.

Flaky TypeScript support

Vue uses an event system for feeding information back to parent components. These are untyped.

VueX for app-wide data storage is untyped by default.

While both these theoretically have solutions to them, the practicality of the solutions are, in my opinion, weak as well. The official Vue docs states that you must define components with the defineComponent global function [1]. Community sources claim you should use class components [2]. None of these solve the issues with VueX which have some community support for types and proper IntelliSense. The two most popular I have investigated are not satisfactory due to the amount of boilerplate needed.

Templating engine dictating flexibility

While you are not necessarily required to use Vue templates for HTML definitions, the Vue way is to use the special Vue templates. In the templates you define loops and conditionals by interleaving HTML attributes. This means that developers are dependent on the template engine in order to solve problems that are perfectly standard programming problems.

React uses distinctly different system called JSX for defining rendered output. Since JSX is purely function calls that are easier to read, developers can express any design pattern that JavaScript is able to express – removing all potential hurdles introduced by a templating engine.

A particular example where the templating engine falters is the inability to store render instructions in variables and pass them around – a very powerful pattern.

Fragmented API and Community

While React’s API have shrunk since the inception of React Hooks, the API of Vue seem to be growing and becoming more fragmented. There are multiple ways of feeding information into components – a developer must choose between binding, events, and props. On top of that there are special treatments for these like syncing, watching, and computed properties. The Vue API and documentation is huge, not because it is strong, but because poor design choices in the core forced the invention of fixes for them. In the case of DoctorUI we seem to be using a mix of Vue 2, Vue Component Class, and Vue Property Decorator, and Quasar to accomplish Vue’s primary purpose – to update the DOM – none of which seem to be community anymore – and is a symptom of the fragmented community in my opinion.

Reactivity system limits rich data usage

For Vue to know when to update the DOM, it decorates all data objects with observers and adds it to its “Reactivity system” [3]. The supported data types are boolean, string, number, array, object, and Date object. This means we cannot have Sets, Maps, or any other rich data structure like improved Date objects [4]. It also becomes difficult when we need to make updates based on non-Vue data since our idea of what needs update does not overlap with the Reactivity System’s and this information is obscured as an implementation detail in Vue.

React have a single rule – when a reference changes updates will occur, and it is agnostic to the data type. This has the implication that no objects must be mutated. While this potentially adds complexity, I deem this to be strictly a lesser evil in all cases, and in most cases a good principle to follow.

Spaghetti execution

Until the release of React Hooks API [6] both Vue and React used a similar approach to handling component lifecycles. Both were class based and had class methods representing events the rendering engine emitted. The lifecycle events used in Vue are beforeCreate, created, beforeMount, mounted, beforeUpdate, updated, beforeDestroy, destroyed. This creates a caveat that in my opinion is a big hurdle for composability and readability – code that sets up something is decoupled from the code needed to clean up [7]. This causes developer strain and memory leaks due to the need to develop hard-to-follow clean-up patterns.

When using React with functional components and hooks, which is standard since React 16.8, everything executes from the top down.

Debugging

The above issue with spaghetti execution also makes debugging more difficult. In order to know what a variable in a template will do, a developer must know where that variable is updated in order to know how it affects the render output. Since in a pure functional component, you can follow the variable reference from the top down, no surprising side effects can take place. Which also means that in order to know where the execution starts, you just have to look for the top of the component.

Another hinderance to debugging is Vue’s reactivity system. Every piece of data you pass around gets wrapped by Vue – it applies getters and setters to properties and upgrades your data to “Vue data” it can observe. This means that all data you put into Vue becomes less intuitive to traverse because you must unwrap all getters lazily in the console. It should also stand out to the seasoned software engineer how bad of a foresight it is for a rendering framework to be reliant on being able to introspect any data a programmer puts into it.

Low importance issues

No public vs. private discrepancy

While we use class components in Vue, we discern between public and private properties. This is superfluous in React.

No special way to solve DOM injection

Vue uses a slot system [5] for components to display arbitrary DOM nodes inside another component. React applies a more direct approach where you simply use a prop typed as a React Node, further simplifying its API.

No “this” keyword

Vue relies on the “this” keyword for much of its functionality. Since React introduced the Hooks API [6] the need for class components and thus the “this” keyword went away. While not inherently evil, it adds complexity when we need to differentiate between bound and unbound methods, and reference data with this.prop inside a class but can use prop without this in templates.

No need to register components

In Vue you must tell a component which components it can use from the scope. React uses a standard JavaScript approach which uses the standard import statement and references the name from the scope.

Opinion

Since the advent of the three big frameworks Angular, React, and Vue I think Vue is the underdog that is liked because it is the most similar to vanilla web development. Angular is the behemoth that try to solve everything for you. React is the slice of tools you need to solve the problem with declarative rendering the right way while still being plain JavaScript.

During this time, I’ve gotten to know all three communities and my assessment is that the React community, especially its core contributors, are the most knowledgeable, and have managed to consistently make future proof decisions and holistically solve UI problems, while Vue and Angular contain a plethora of bad ideas.

Further, for me personally, I have thousands of hours invested in both knowledge and battletested code, which will help me support the company better in fast development. This is especially true for the mobile app format where I have recently spent a year full time in building PWA compatible web apps for Einride.

React Caveats

There are some known annoyances with React too of course. In the community you often read about developers struggling with the dependency array when it comes to array hooks. It is completely true that keeping the dependency array in order can be an ordeal, especially for developers that are not comfortable with the principles around reference equality and value equality.

This can take some time to get used to. Personally, I have not found this annoying when applying best practices like ensuring all references are stable and using the React Hook lint rules that comes bundled with React developing environments.

Conclusion

While Vue is a good tool, it is built to resemble vanilla web development and provide a low threshold of entry. A lot of patterns you expect to be able to use is difficult to implement in Vue due to them being dependent on support from the Vue core. Since React is just JavaScript it will always be compatible with TypeScript, including perfect type inference, and developers can always rely on being able to use common, as well as novel patterns to solve rendering problems.

I also think that the decision to let a rendering framework use strictly pure functions is such an important move for robust, composable, and predictable UI development that we absolutely should be on this train.

I do not think we should rebuild internal tools, but I think Vue is going to be a cause of constant uphill battles and frustration in the long term, especially for experienced developers, and I think user interfaces that are to be used by end users must be converted to React in order to meet high standards from both customers and developers.

References

  1. https://v3.vuejs.org/guide/typescript-support.html#defining-vue-components
  2. https://dev.to/kennyrafael/you-should-be-using-vue-class-component-5ckl
  3. https://vuejs.org/v2/guide/reactivity.html
  4. https://moment.github.io/luxon/
  5. https://vuejs.org/v2/guide/components-slots.html
  6. https://reactjs.org/docs/hooks-reference.html
  7. https://gist.github.com/pomle/a5da98085230dcb81de9486772d63b99
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment