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:
- A clearly segmented component structure - HTML template, JS and CSS.
- 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!
Top comments (26)
I tried react but disliked the experience, it doesn't has directives or a proper separation between markup, style and logic. That's why I prefer Angular and Vue to React.
I have to admit that markup and logic are together in React, but they are together since the React's concept, so we couldn't create a library that separate them and continue to be React-like.
However, you can separate styles very well: You can put them in another file inside the same folder you put your React Component, like
SubscriptionButton/index.jsx
andSubscriptionButton/styles.css
. You can do that with regular CSS, CSS-in-JS or CSS Modules, besides that with SASS too. But, you could do all that inside the same component's file. The freedom of choice is yours.Therefore, you no longer have a component with 8 lines of markup and 40 lines of style, which would pollute the component and lead to creating a huge file for a component with just 8 lines of markup. Personally, I would like to say the same about Vue, but I haven't found how to do this separation in 2 files until the moment. Anyways, because of that I think it's incorrect to say that you can't separate style from the rest in React.
Well, style is the only thing you can separate properly
Actually, you can modulate everything. Take Airbnb as project patterns example.
You still have extensions like ESlint to apply these modulation patterns, and guarantee you will separate it correctly.
It's not the same as using Vue or Angular, I'd rather not have to configure a framework so it can do what others can do by default.
I must admit I disliked the experience at first, but I guess that's a common reaction to change. It took me about 2 weeks of reading and playing around with React before I really began to understand what was happening. In those two weeks, I was evangelising to colleagues about how Vue was cleaner and more organised. Do I still believe Vue is more organised? Yes I do.
But I suppose the reality is that your employment options tend to be a bigger determinant of what you should be learning than any individual developer's opinion. So React vs Vue? π€·
Vue, I'd rather use a library/framework that has a coding paradigm I prefer. There might be more react jobs available but I don't care since I know both Vue and Angular.
I think at this point, the Hooks API has done a disservice to the JS developer community in teaching anti-patterns. There's so much sloppy code out there with the multiple nested hooks I keep seeing. I mean, we're treating functions like classes when we should just be using React classes in the first place. If we have to keep using functions, I'd rather continue using Redux, given its readability works better with React's one-way data flow style
This comparison focuses on the 'Options' API of Vue 2. I am interested in your thoughts on Vue 3 using the 'Composition' API (and script setup) which feels, in some ways, closer to React hooks with some of Svelte's conciseness thrown in.
Nice write up of your experiences!
Tbh, I haven't had the opportunity to work with the Composition API. Correct me if I'm wrong, from what I understand the Composition API does not remove the Options API functionality. It is an additive feature that helps developers to break up complex components into reusable hooks (as you say very similar to React hooks). If so, the glossary above is still relevant, the only difference being that each map maps to both the Vue option and the equivalent API within Vue composables.
I personally am a fan of React hooks. I write quite a few custom hooks of my own and if Vue composables are as flexible as React hooks, and I'm sure they can be written to be as flexible, then I'd definitely be using composables where appropriate.
Haven't tried Svelte out yet but just going through the getting started guide, it looks like a framework that's even closer to vanilla HTML/CSS/JS than Vue is. Will definitely spend some time on it when I can!
Correct, you can use both the Options API and the Composition APIs in the same app.
There is a community library that brings together many common composables for easy re-use. Having used it in a couple apps, I can say it's wonderful and really proves out the way they've been designed for Vue 3.
vueuse.org/functions.html
Here's some examples of the
<script setup>
syntax, which I've also adopted and found to be great for removing boilerplate.v3.vuejs.org/api/sfc-script-setup....
Nice article i have tried to learn React but because of it's confusing syntax i stopped and started learning Vue and i am glad that my decision was right.... as Vue is a Great Framework and it should be used more then react to increase it's power with it's simplicity
Another huge advantage of Vue is that you can use a react-like render function if you have a complex component.
React forces you to use render by default so lots of simple components are built with spaghetti JS blocks.
I worked with Vue for several years (and still do on my spare time, utilizing latest features). And have to work with React for a year now.
Not sure how React development may be any faster.
Also, that hell of a mix of logic and template in JSX.
No out of box caching of components (no, keys don't keep you from re-render, even if props don't change).
No out of box reactivity. Vue tracks dependencies for you. React wants you to track dependencies yourself. This often leads to bugs.
I am forced to either extract styles to a separate file, which I hate to do, as I love to keep all the component's stuff in it's file, OR to use some you-name-it library, as React doesn't support it out of box.
At least, there's MobX to save us from Redux hell, where you need to fight a dragon to make it work with async/await, and it's boilerplate, low performance and GC overkill.
I will never-ever use React to start my own project. I prefer using tools with no boilerplate. Tools, that don't make me fight them or overload with tons of libs to make them work the intended way.
Vue definitely is the apple of my eye. Provide/inject, composition API, script setup, upcoming with RFC, but already utilizable $ref() and $computed(), Pinia. I never met better DX.
Honestly, I hate it when my company picks React for a project just because "there's more React than Vue developers out there". Of course there are! Because of such company decisions. It's inertial popularity of a more complex tool, that doesn't offer any real benefits (please correct me if I am wrong, I haven't yet met anything in React that Vue couldn't do with same or less effort). Please don't use popular tools. Use better tools and make them the popular ones!
I used to be quite fanatical about VueJS and disliked ReactJS. But after using both for awhile, I realize that it is not really the language.
Poor implementations of either framework can lead to bad developer experiences.
You need to be careful about major version changes too, e.g. VueJS 2 to 3, plugins build for version 2 most likely would not work for version 3, but guess what... you actually do not need to use those plugins... e.g. instead of vue-leaflet, just use leaflet directly...
For ReactJS, have to be careful on things like HOC, if you wrap many layers, changes and fixes will be painful. However, It was fortunate that Class and Hooks components could work in same code base.
I've been using React for a long time, and I totally agree with the 5 five struggles you mentioned here.
I'm currently learning Vue, and I find it to be so much more self-explanatory than React. In addition, React has way more boilerplate code (such as the work you have to do in order to achieve two-way binding), which makes it harder for beginners to understand.
I can not wait to discover more about Vue in the following days. So far, I've found multiple upsides over React (even though React has its own ones) and I have no doubt that the list will continue to expand. ππ»
For me one of the biggest pain points when moving from Vue to React is the lack of
<v-for>
,<v-if>
and the like.Well, it shouldn't be a pain. In React you just need to use JS features like
map
andif
to do the same you used to do with<v-for>
and<v-if>
. The main difference is that by one hand Vue re-invented the wheel throught providing his own style to do ifs and loops, by the other hand React use native features that already exists in JavaScript.I think this barrier of how to do loops and ifs should be lower because you don't have to learn the features that the framework has created to do this because you already know them in JS.
Thanks, this a great article, i use vue but i would like to learn react at some point.