5 things I struggled with when learning React with a Vue background

Initial state

Having worked with Vue for the majority of the past 3 years, I got very used to the Vue syntax and libraries and became very comfortable with the framework. Vue was easy to pick up mainly due to two reasons:

  1. A clearly segmented component structure - HTML template, JS and CSS.
  2. Intuitively named options within the JS segment - components, props, data, computed, methods, watch and the lifecycle hooks.

Arguably, anyone with a HTML/CSS background studying a well-written Vue component could make a good guess of what it does and how it works without referring to documentation. A relative beginner in programming would also find the intuitively named options very helpful.

Mutation

Fast forward to a year ago, my knowledge of React was limited to the few articles I read comparing Vue and React and which to use (there are many and mostly not immediately appreciable if you have never used both) and some dabbling with creating simple components in React following the getting started guide. It all seemed fairly straightforward. I mean, how different can the two frameworks be, right?

Then came the opportunity to really pick React up when I moved jobs. And I was stupefied.

This article aims to help others (with and without a Vue background) understand React functional components and to get up to speed with React concepts more quickly. It does not attempt to compare Vue and React as competing frameworks and its intention is not to rank one over the other.

The 5 things I struggled with

1. Code structure

In Vue, there are three segments to every component:

  • <template> (HTML/JSX),
  • <script> (JS structured within intuitively named options),
  • <style> (CSS).

It is very similar to a typical HTML page's layout, albeit with style in the "footer" instead of "head".

In React functional components, the main underlying key is that component code runs sequentially from top to bottom, like a typical JS script, and returns a value, usually HTML/JSX. Coming from Vue, the structure looked like:

  • One big mess (JS - unstructured interspersion of hooks and methods),
  • return (HTML/JSX)

At first impressions, without a fixed structure for the JS segment, trying to understand code written by others was not easy, especially if there were no comments. It did not help that the built-in hooks are named so technically (useEffect, useMemo, useCallback) and that it is impossible to understand what the second argument in the aforementioned hooks was for without referring to documentation. So while these hooks are more flexible and hence reusable than their Vue counterparts (watch - useEffect, computed - useMemo and useCallback, mounted - hooks with an empty second argument), they are also much less interpretable.

That said, as I started writing my own components, I began to realise that while there was no fixed structure, there were certain rules (such as the Rules of Hooks) that made my code conform to a non-explicitly defined structure. In all my components, I tended to define all states used within the component and place all setup code just below. Following that, I found myself structuring the code in blocks of logical concerns, very similarly to how I structured my methods option in Vue.

I then realised that what looked to be one big mess to my uninitiated self, actually had a general structure across projects - I just needed to understand the functionality and use cases of hooks more intimately before I could decipher the React component structure. And this is not a steep learning curve if you already understand basic computing concepts (side effects, memoization, callbacks).

For those coming from Vue, here's a quick glossary to help understand how certain hooks translate to Vue concepts.

React Hook Vue option
useState data
useEffect(, [x]) watch
useCallback(, [x]) computed
useMemo(, [x]) computed
useEffect(, []), useCallback(, []), useMemo(, []) mounted
return function called within useEffect(... return function(), []) unmounted

And for those who don't have a background in Vue, here's a summary of what I learned about code structure in React functional components.

  • Some methods, constants and styles can be defined outside the scope of a component (typically at the top of a file). These are optimisations so that said objects are not re-created on every render.
  • Components usually begin with retrieving props, defining states and importing reusable methods/helpers. This is very similar to how JS files are structured.
  • Setup methods usually come next: setting up states on mounting, computing derived values, fetching data.
  • All other logic used within the component - hopefully organised by logical concerns.
  • If you're wondering where CSS comes in, React doesn't dictate how CSS is used. You are free to import CSS files, define inline styles or use a CSS-in-JS library.

2. Lifecycle methods

One of Vue's key concepts that I truly appreciate is the clear definition and documentation of the lifecycle of a component. React does attempt to document this as well, but not to the extent that Vue does, and the API only works for class components. With React's shift towards functional components, lifecycle methods are no longer as easily accessible.

When I started out with React, one of the first concepts I wanted to understand was the React component lifecycle. Having got used to Vue's lifecycle hooks, I was looking for something similar in React functional components, but there is no documentation for this within the State and Lifecycle section of the official React guides. And even for class components, React does not make the entire lifecycle accessible like Vue does.

However, in Vue, the lifecycle methods I tend to use the most are mounted and unmounted. So, I was really looking for an equivalent in React functional components. On further Googling, I found out that the useEffect hook could function the same way that the mounted/unmounted hooks do in Vue. While not as intuitive, it was merely a matter of adapting to the React API. At least I had a solution for my setup and teardown methods.

In short, what I learned here was that in React functional components, the setup phase (usually created/mounted in Vue) can be written with useEffect(, []), while the teardown phase (unmounted in Vue) can be written with useEffect(... return function(), []). While other lifecycle methods cannot be accessed in React, they are probably not required frequently enough to be a big bother.

3. Two-way binding vs one-way binding

In Vue, the v-model directive allows for two-way binding for input elements. From a purely lazy (perhaps also maintainability) standpoint, this saves on a lot of boilerplate code. While I don't want to get into the debate about whether two-way binding or one-way binding is better, it was a definite annoyance for me to have to write what seemed like boilerplate methods to update state when switching to React. This is compounded by the fact that doing React right meant not mutating states but creating copies and re-setting states. This meant that the code for forms in React was much longer than the equivalent in Vue.

For those without context, one of React's core facets is one-way data binding, which in short means that data flows only in one direction. This allows React to more effectively determine whether a state has changed and what caused the change.

In complex Vue components, you would occasionally run into situations where the DOM does not update despite an observable being updated. Rare, but it happens and is annoying to debug. However, one-way data binding in React eliminates such issues because you trigger a DOM update manually every time you call a setState. The downside to this is that you have to write the code to trigger the re-render (setState), something you don't have to do when using Vue.

In truth, this was largely just an annoyance when I first started out with React. I have since built reusable components and I no longer write boilerplate for forms any more. In fact, with FormBlob, I can create any form I need in 2 minutes.

4. Scoped Styling (CSS)

Scoped styling in Vue is very straightforward. If you're familiar with HTML/CSS, it all comes very naturally - define a class on your HTML element, set CSS styles for that class in the <style scoped> segment.

Scoped styling is useful to ensure that styles are only applied within the component it is defined in. This allows us to reuse class names in multiple components without being concerned that styles defined elsewhere would interfere. This is especially powerful for building component libraries that are intended for use across multiple projects.

With React, there is no pre-defined recommendation on how CSS is applied. You are free to import CSS files, use inline styles or use CSS-in-JS libraries. Some CSS-in-JS libraries such as jss or emotion have become very popular and are used in many React projects. However, as with any third party library, there is always a learning curve, especially when defining reusable styles.

Before I get berated for being too spoilt, remember that this is my experience moving from Vue to React. In Vue, I did not have to re-learn any Vue-specific style libraries and I could achieve scoped styling with reusable class names out of the box using vanilla CSS. In React, the process to achieve a similar result is arguably more tedious, whether it is writing your own CSS file or using third party libraries.

5. Reference resources and libraries

One of the arguments going for React is always that React, being the more popular framework has deeper online resources and support that you can tap into. In my experience, having only started working with React after the launch of functional components, this is not true.

React, having been around for so long with so many versions (it's at v17 now) has a deep resource of outdated solutions and dated libraries. I find that it is considerably easier to find solutions and relevant libraries for Vue (only at v3 now) than for React. Since working with React, I find myself spending significantly more time Googling to find a solution that solves my needs than when I was working with Vue. From a personal point of view, it is something I struggled with when starting out in React. A large number of solutions that I stumble upon simply won't work and it takes more time to find something that does. But that may be down to my inadequate Googling skills!

Conclusion

I have used both Vue and React to build complex apps and to be honest, I'm now more familiar with React having used it on a day to day basis for the past year. If I were to start a new project now, I would do it with React simply because I'd be able to deliver a complete app much quicker in React than in Vue right now. I have since got much more comfortable with React and its quirks and have no strong preference for either Vue or React as a framework.

This article is a personal anecdote and is not meant to be an objective comparison between Vue and React. My intent here is to share what I've learnt transitioning from Vue to React and hopefully help others who are doing the same, or who are looking to learn React. I welcome any views and experiences contrary to what I have experienced and it is not my intention to make any sweeping statement or claim (even if within the article it sounds that way). I am a student of programming and always will be and am glad to learn from anyone.

Cheers!

23