React vs Vue: Which framework to choose? [Developer’s perspective]
While we can find many articles trying to compare these two, we were struggling to find one which would give us a definite answer - which framework is a better choice, and why? We use both frameworks for various projects, from simple web development to mobile apps. We hope this article will give you clear suggestions when you need Vue and when it's better to use React.
The main difference between React and Vue: React is a library, Vue is a framework
Here’s the main strength of Vue. If you’re new to React you’ll spend most of your time reading about possible solutions and common ways to solve problems. Moreover, you’ll find many different solutions for every problem you face. On the other hand, in Vue, everything you need is specified in the official documentation. The whole ecosystem is official. You have Vuex and Vue Router and no reasonable alternatives to them. Even style guides are included. In React you’ll start by wondering if you should use Thunk or maybe Sagas with Redux, and this is just the beginning of many questions that will come up.
You may think that having multiple options is a better choice, but in reality, you’ll most likely find yourself discussing with your colleagues or trying to convince your team leader to use library X over library Y. Everyone has their own opinions, and no clear guideline when selecting React utility packages requires a very mature team that can handle the responsibility and knows exactly what they want to do.
Which one is harder to learn: React or Vue?
In Vue, you will learn Vue. The framework. Every component will look very similar. Vue will always try to show you the best approach to solve the problem. You’ll spend a little time learning all the features of the Vue template language. But after all, for us, Vue templates look better than JSX. It’s empowered HTML, not HTML in JS. Another big advantage is that if you’ll switch to another project it will look very familiar. You’ll already know most of the solutions and patterns, and it’s easy for your peers to give you a good code review.
If you change projects in React it’s highly probable that you’ll have to learn new libraries, like mobx. You’ll need to ask what approaches are used in a new project. Does your team prefer to keep data in a global state now or maybe they want to pass it through the props? Do they use higher-order components? Functional or class components? Why?
After all, Vue has an easier learning curve.
Coding experience comparison of Vue and React
When you work on code you want to be able to make it as readable and maintainable as it’s possible, you want to avoid boilerplate and you don’t want to waste time on long debugging sessions. That’s basically how our coding experience differs between Vue and React.
When it comes to debugging, both frameworks provide their own debugging tools. While in most cases they work similarly, we find it better to read DOM in Vue’s debug tools as it doesn’t list all HTML nodes but only components (by their names).
Writing the DOM
Vue’s template syntax is straightforward to use and in most cases, we did not need customizing it in any way (but you can - take a look at https://vuejs.org/v2/guide/custom-directive.html). Just spend one afternoon learning it, and you are all set. We are also big proponents of the single responsibility principle, and having a template that is not holding any logic at all is a great thing. Once again, Vue is enforcing this pattern from the very beginning of your development journey. In React, you have to find good practices like this by yourself, and then force everyone around you to follow them too.
Let’s take a moment and look more closely at Vue’s way of styling. As developers, we have worked with multiple solutions - from BEM used in standard CSS, to Sass or even Stylus. And there are two problems that they all wanted to solve, but it only became possible with Vue:
- Styles should be scoped for components. As modern frontend developers, we think and breathe with components, these are our atomic parts of applications. However, I wasn’t convinced to scoping styles at first glance, because I was too familiar with long, global stylesheets. It turned out to be one of the most useful things in Vue, and I constantly try to replicate it with styled-components in React projects. Of course, we still want to use global styles in some places - think `reset.css` or theming - in Vue we can easily import these globals alongside scoped ones. Even better - we can use global variables in our scoped component styles.
- We want to move away from simple CSS for a more modern solution - in Ulam Labs, we prefer `Sass`. This couldn’t be simpler in Vue - with literally one keyword, you can choose languages like `Sass`, `Stylus`, `Scss`... And it’s defined on a component basis, so you can start refactoring one piece of your application without having to worry about collapsing others.
Once you find yourself writing scoped styles in Vue and you take a look at a typical React project, you can’t help but feel like you are missing something. It’s hard to replicate Vue’s scoped solution in React - it requires boilerplate and additional tools, and as always, understanding of this principle by your teammates.
We can say that Vue has a more intuitive solution for data binding. In Vue, you pass data further using props. It’s the same in React. But when a child component wants to push some data to the parent in Vue you have an event system that is very straightforward and encourages loose coupling architecture by making the developer focus on one component at a time. This is a plug and play way of work.
In React, you have callbacks that give you the same possibilities, but this solution makes you think about the callback’s implementation from the outer scope while working on a child component. Oftentimes, inexperienced React developers will solve problems using antipatterns like `getDerivedStateFromProps`, simply because there is no other clear way of doing it.
In Vue, in almost all cases you will use Vuex to manage the global state. It is behaviorally similar to React’s Redux, with one important difference - it supports asynchronous actions out of the box. This is a huge thing since you don’t have to think about another third party middleware like Saga to implement common tasks.
In React, there are multiple great solutions, but they don’t necessarily work well together. For example - there is this great library, `mobx-state-tree`. But will it work well within a TypeScript project? We are not sure, this is yet another research to make.
There is one more thing to consider, and it’s the need for a global state in the first place. We are very strict about the usage of Vuex in our project - we are using it almost exclusively when data must be available in multiple disconnected places in our application, be it current user information or items in our cart. But in react, there is a tendency of overusing global state to perform a lot of small tasks that could’ve been done using props - for example performing every API request in Redux even if it’s used only in one component.
Separation of concerns
We have already expressed that Vue has a beautiful way of separating styles, structure, and logic - all written per component, in the specific parts of the `.vue` file. We also described problems that come with tangled React’s JSX and unclear callback props.
However, this separation is only true on the component level. We must say that with the introduction of hooks to React, logic can be extracted from its components fairly easily - even to the point that almost all of the logic resides outside of the components. This is great and provides nice testability and scalability for application.
This behavior will be almost identical with the Composition API in Vue 3, but right now, as Vue3 is not released yet, Vue lacks a good way of extracting logic outside of component files. The data and methods are tightly coupled with components, and existing solutions like mixins are not flexible enough to support all of the possible problems.
As a framework, Vue needs less boilerplate than React. In React you spend much time on proper handling lifecycle methods and preventing infinite loops or proper state handling and binding. In Vue, it’s handled automatically. You can watch properties and run some code only if Vue detects that the property has changed, so you don’t have to find out which property has changed manually. If you modify another value in the watch’s listener method which will lead to an infinite loop it will probably be really easy to find it by reading code, but we can’t say the same about React.
In React, you as a developer are responsible for updating state, so you have to reassign it in a proper way to prevent things from getting out of sync. In Vue, you can modify only specific data parts and everything is synced automatically, but it also has a downside as it introduces some vue-specific edge cases when you need to deal with objects or lists in a special way to keep it synced.
One more thing, that is working just fine in Vue while giving a massive headache in React, is the ease of creation of controlled inputs in the form. Vue gives us the simple yet powerful `v-model` directive that handles most of the everyday cases perfectly. In React, the need of creating proper handlers for things as simple as reading input data to state is a tedious task, and in our opinion, you are almost always creating the implementation of ‘v-model’... but on your own.
TypeScript is a great tool and it’s fairly easy to assume that it will be a standard to write every piece of code in TypeScript in the future. This is also great leverage that React has over Vue, at least until Vue 3 comes out.
In React, the typescript works out of the box. Since React heavily insists on using plain JS to perform every piece of logic, conversion to TS comes naturally - there are no problems with it within the render templates or when passing props. The usage of the Higher-Order Component pattern, along with `connect` methods are working well with TypeScript - you can add types to your props, and you are communicating with the global state via props anyway.
For Vue, unfortunately, things look different. Although the basic TS usage is fairly easy to configure, problems arise when you start trying to type props or global state. Vue 2 has it’s own system of prop types, which is not necessarily compatible with TypeScript. And Vuex handlers, like `mapState` or `mapGetters`, are confusing for TS because they use raw strings to select data from the state.
These problems will likely be resolved in Vue 3, which will support TypeScript out of the box (in fact, usage of TS in Vue is one of the main reasons for a new Vue version.) We look forward to it, but for now, React is the winner here.
Mobile apps development with React and Vue
In Vue, you can try with Ionic but it can be very challenging in some situations since community support and documentation are close to none here. There’s also NativeScript but we can’t say much about it yet.
Scaling with React or Vue?
As for now, when Vue 3 is not released yet, React is capable of scale better than Vue. The reason is simple. React is a library. It gives developers more choice and when your projects grow and there are not 3 but 30 developers involved it’s easier to split components into many parts. With React, you can play with your components and code structure as you want so you can prepare it for growing big. In Vue, you may end up decrypting other programmer’s tricks and cheats on the framework. You may need the context of the component to understand how some separated logic may work.
All common test frameworks behave similarly in both frameworks. For tests we are using Cypress, JEST, and Storybook daily, and they work fine. One advantage of React in testing is that because these tools were first constructed for React, the community is bigger and you will more likely find answers to your questions if you are having trouble testing in React. Also, JEST is better documented with React examples.
Community size and support for React and Vue
You can read everywhere that React has a bigger community. However, when it comes to programming web apps, we have never suffered from a lack of components or community support in Vue. In terms of component libraries both Vue and React offer similar ones; popular libraries like Bootstrap have bindings to both frameworks. We have never waited for solving an issue in any Vue component. Vue tools are production-ready as well as React one’s.
The problems with lack of support in Vue may be encountered when developing a very atypical application with uncommon third party libraries or using a fairly new tool in the vue world, like Ionic. So in that case, we suggest checking first if the tool we want to use is already properly released for Vue.
To sum up, what to choose: Vue or React?
Jakub: When I start a new project I never have to think much. Vue is an obvious choice for me. I want to see a well-known code structure after a few commits and I want to solve all the prosaic problems with a few well-known lines of code. In Vue, I feel like I’m composing the new app while in React I feel like I need to plan everything and make decisions in every step.
Michał: The freedom that React gives is in my opinion the main downside of it. It requires discipline, knowledge, and experience to avoid traps, pitfalls, and anti-patterns. In Vue, on the other hand, clear guidelines will help even inexperienced developers to contribute good quality code to the codebase.
It’s clear that we prefer Vue, but it’d be unfair not to sum up the cases when we suggest considering using React instead:
- Creating a mobile app. React Native community is thriving, and if you already know React well, this is a perfect choice.
- You simply can’t live without TypeScript (and you read this before Vue3 is released)
- You are going for a very specific solution, that is originally built over React (an example may be a JAMstack site, where Gatsby.js is a default - and best - choice)
- You are going to build an app that is atypical, specifically in terms of UI. When you build a custom touch panel for a new SpaceX rocket launcher, typical “dashboard-like” components and parent-child logic may not work. You may choose React for the freedom and total control it gives.
Otherwise, we suggest that you go for Vue. You’ll struggle less, develop quickly and you’ll have more fun along the way.