React and Vue are two of the leading frameworks for creating JavaScript-enabled websites and applications, and each has its devoted fan base. At their core, both frameworks have the same goal: to make it easier to build websites and applications by removing the need for developers to manually write code to keep user interfaces and data in sync.
The two frameworks tackle this problem in very different ways, however.
If you're wondering whether to use React or Vue for your next project, this post delves into what I think are some of the pros and cons of the frameworks.
Before React, web applications had reached a point where building them mostly consisted of describing web pages in HTML, gathering data, combining the HTML with the data utilizing a server-side technology, and adding JavaScript to the page to make further changes client-side, such as sending and retrieving more data and updating pages based on user interaction.
As users visited pages of an application, a page would be rendered on the server, sent to the user's browser, and the browser would execute the JavaScript, making the page interactive.
HTML and CSS were the primary underlying technologies utilized in building web applications, and JavaScript played an essential but minimized role. JavaScript was mostly used to send and retrieve data and locate HTML nodes and update them dynamically. Initially, this process could be very cumbersome due to lack of true standards between browsers and variations in implementations even when standards existed, but advancements such as JQuery helped make HTML plus JavaScript a viable option for building applications for the web.
React's great innovation involved inverting the importance of the roles HTML and JavaScript played in building web applications. Rather than building web applications where pages featured HTML as the primary technology and JavaScript was added on, React made JavaScript the primary technology and minimized the role that HTML played in the process of building web applications.
Reversing the roles of JS and HTML meant that completely client-side applications could be built more easily. The fact that everything was based in JavaScript meant that it became easy to query data from external sources using standard JavaScript techniques and then pass it on to the various components created using React. With mechanisms for updating UI based on "state" within components, React took building single page applications to the next level.
Vue, on the other hand, enables building web applications while retaining a more traditional composition of technologies.
Pages are primarily described in HTML, and a data model and interactivity based on JavaScript are layered on top of it. Vue embraces technologies that enabled web pages to become web applications in the first place, while enhancing them to make it easier for developers to provide interactive user interfaces.
Vue makes it easier than traditional HTML to split pages into various components that can be wired together and provides each component with the ability to maintain a data model where changes to the data are reflected in automatic updates of the component's interface. To accomplish these updates, a simple but effective templating system is utilized.
Similar to React, Vue can also be utilized to build single page applications.
In some ways, it can be difficult to compare React to Vue because both frameworks have a number of ways in which they can be utilized.
For instance, React can be utilized in a standard HTML page by including it via a script tag. Most developers wouldn't want to utilize React in this manner, however, because it means giving up one of React's most compelling technology integrations: JSX.
JSX is a technology that enables describing HTML within JavaScript. It lets you do things like assign what looks like HTML to JS variables, like so:
let myDiv = <div>hello!</div>
While this looks simple on the surface, note that what's being assigned to the variable myDiv is neither a string nor template literal. The browser doesn't actually know what's being assigned to the variable, so it's necessary to have an intermediate step known as transpilation to change that statement into code that the browser can understand.
Transpilation, along with other important features that are considered standard with a React-based application, require starting with a JavaScript-based toolchain that enables features such as code transpilation and code splitting. Technically, these features aren't really part of React, but from a practical perspective, they have largely become synonymous with building a React application. So, trying to compare React to Vue without taking these features into consideration as part of React wouldn't really be fair to React.
Vue, in contrast, works well as either a standalone framework that integrates directly into a web page, or as part of a larger, JavaScript-based application.
When evaluating the two frameworks, one important consideration is how easy it is to get started with them. As noted, Vue can be inserted directly into an existing HTML page while still retaining the characteristics of how it works. React, on the other hand, requires transpilation for features such as JSX. Both, however, have CLIs available.
CLIs have become commonplace for scaffolding programming projects, from JavaScript to Microsoft's .NET Core platform. As technologies gain more and more features, they tend to require a lot more setup code. That setup code, in turn, often tends to be repetitive. If you need code splitting and transpilation for one project, it's highly likely that you'll need those features for a project in the future too.
Create React App (CRA) is the primary CLI for React, while Vue directly offers its own CLI.
Both tools have similar goals for their respective framework: to make starting and maintaining a new project easy. And both tools accomplish, in my opinion, what they set out to do.
Despite the fact that Vue works well in standard HTML, without additional tooling, Vue's CLI brings all the features I'd expect for a modern, client-side application that is, in many ways, comparable to the feature set implemented in a Create React App project.
One of the major benefits of using a modern framework for building applications is being able to split the application into components that interact with one another.
Components in both frameworks are very similar and work like Web Component custom elements in HTML.
<my-component></my-component>
Although implementing components is an entirely different experience in React vs Vue, both frameworks have similar mechanisms for passing data to components. When passing data between components, both frameworks generally utilize attributes, which both frameworks refer to as props.
Once you create a component in either framework, passing data to a custom component may be as simple as:
<my-component color="red"></my-component>
In React, dynamically binding prop values is easy:
<my-component color={color}></my-component>
In Vue, there are a number of different attributes for implementing different functionality, but for dynamic props, using the v-bind modifier is close to the functionality of React:
<my-component v-bind:color="color"></my-component>
Where React and Vue really diverge with respect to components is their respective methods for describing the data that components can receive, how they maintain state, and how the HTML structure of components is described.
With React, there are two options: class-based components, or function components with hooks.
Class-based components are similar in nature to web components. React's class-based components provide lifecycle methods that enable developers to take certain actions in response to certain component-level events. Additionally, React provides a mechanism for tracking the state of certain variables within the class and re-rendering the component every time the state (or the component's props) changes.
Function components are a more modern implementation of components within React and enable creating more streamlined components. These components basically consist of a function that returns JSX. For example:
function MyComponent(props) {
return(<div>
The provided color is {props.color}!
</div>)
}
In Vue, components are much more declarative in nature. Specifying a component starts, for instance, with telling Vue about the component's props, the data it should track, and what the component should render.
Here's an example of a similar component created in Vue:
Vue.component('my-component', {
props:['color'],
template:`
<div>
The provided color is {{color}}!
</div>
`
})
Whether you prefer React's or Vue's components is probably simply a matter of preference. As discussed earlier, JSX in React will require a transpilation step. Vue's components, on the other hand, just work in HTML out of the box.
Vue components are typically implemented leveraging standard web technologies, integrating concepts like flow control into the HTML of the component templates, whereas React components enable advanced programmatic control via their typical integration with JSX.
How and where you declare components will differ in React and Vue based on implementation, but, with appropriate tooling, both are capable of supporting components that live in their own files and are imported into other components.
Your preference for Vue's or React's components will probably come down to whether you prefer JSX or HTML among other factors.
Both React and Vue provide mechanisms for maintaining the internal state of a component.
Class-based React utilizes a setState
method that accepts an object which contains
the entire state of the component.
React with functional components and hooks (the more modern React) encourages
keeping track of state via the useState()
hook. The useState()
hook returns an object and a setter function to update the state of an object. In general,
my opinion is that this type of state tracking feels far more natural since each piece of
data that's being tracked is more along the lines of a single variable.
Vue uses a more declarative approach. When a component is instantiated, a data object is provided up front with all the trackable members. The members of the object will be tracked, and changes within the members will subsequently cause the Vue component to update.
In Vue, state changes and other functionality such as methods or computed functions — although separate — are somewhat tied together since they all have to be defined as part of the options object when creating a component.
In Vue, various functionality necessary to the component is defined in different child objects of the object passed to a component. For instance, methods go into a 'methods' object and computed properties go into a 'computed' object.
In my opinion, the separation of functionality into various member objects on the Vue component object creates a disjointed experience. In React, obtaining data and composing that data into a template that will be rendered can be a streamlined process due to JSX. In Vue, data, methods and templates are described in separate member objects of the object passed to a Vue component at creation, which can lead to unclear relationships between the various pieces of functionality implemented by the component. That’s not say that the same isn’t true of React components, but I personally find it easier to write clearly structured code than to document how various related but loosely organized pieces of functionality interact with one another.
Some developers love JSX, and others don't. I've personally found it to be very beneficial in helping create streamlined components that are easy to read. Additionally, I think it helps significantly reduce repetitive code and make it clear what's happening. Here's an example:
export function MyComponent(props) {
switch(props.color.toLowerCase()) {
case "red":
case "purple":
return <div>It's a great color!</div>
default:
return <div>It's not a great color!</div>
}
}
In Vue:
Vue.component('my-component', {
props:['color'],
template:`
<div v-if="color.toLowerCase() === 'red' || color.toLowerCase() === 'purple'">
It's a great color!
</div>
<div v-else>
return <div>It's not a great color!</div>
</div>
`
})
When you're surfing for new web technologies, it can be easy to fall into the trap of thinking that implementing new technologies is of paramount importance — because, of course, all those shiny new features you're finding will obviously make it easier to develop applications.
In many cases, yes, a lot of new technologies can make it easier to develop new applications. For many organizations dealing with old applications, however, there's a balance between sticking with what works and keeping up with change so as not to be left too far behind.
When comparing whether it's easier to upgrade an existing application to a more modern stack with React or Vue, my opinion is that Vue is the better choice. Vue can be easily added to an existing web page via a script tag and results in a fully functional framework for dynamically updating user interfaces that doesn't feel like it's missing anything.
The initial experience of using the core functionality of the Vue framework is largely consistent with the experience of using it with a more advanced, JavaScript-based toolchain.
Additionally, Vue doesn't pose a major challenge to integrating the framework with traditional server-side applications. Vue offers a server-side rendering framework, but it's also possible to continue utilizing a standard server-side application to generate pages while layering Vue on top of the results that are sent to the user's browser.
For instance, let's see one way this might work with Express (a NodeJS server framework), Pug (a view engine with templating language that we'll use in combination with Express), and Vue. In this example, Express is used server-side in combination with Pug to generate pages that are sent to the user. Then, Vue is layered on top.
Imagine that there's a route set up in Express. As you may know, Express's
render()
function takes a data object that can be used to pass data to a view.
Let's assume that there is a data function that looks something like:
{
message:"Hello there!"
}
This data will be passed to the view that's used to render the route. Pug, a templating view engine, has access to the data. To render the data passed to the page in an HTML text content element, Pug works like so:
div This is a very important message: #{message}
The #{message} instruction will result in Pug placing HTML-escaped data inside the div. So, the result is a page that renders with the initial message passed from the route.
Now, what if I wanted to layer Vue on top of the page that's rendered by the server so that the message element could be dynamically altered after the page has loaded?
Assuming that the appropriate Vue script has already been loaded by the document, a view such as the following could be used:
Caution: It's important to properly escape data when inserting it into web pages. In the example below, data is being inserted in multiple contexts, both server-side and client-side. Different contexts may require different escape techniques.
div(id="element1")
span This is a very important message:
span(id="messageSpan") #{message}
div Enter a new message:
input(type="text" v-model="message")
script.
window.onload = function() {
document.getElementById("messageSpan").textContent="{{message}}"
new Vue({
el:"#element1",
data: {
message:""
}
}
In the above code, the name is added to the messageSpan element before
the page is served from the server. Then, because Vue executes as JavaScript
after the page loads, the code can set the textContent of the messageSpan to
{{message}}
and have Vue evaluate the content of the message. The
message data element is tied to the input element specified in the Pug template, so
when the user types a new message in the input textbox, it will overwrite the
value that was served by the server.
The above example is merely meant to demonstrate that Vue can be layered onto existing server-side technologies without a great deal of setup or technological change. Such an approach wouldn't necessarily be my preference for starting new applications.
React, on the other hand, when implemented via a direct script tag, loses the ability to use JSX. JSX, while not required for React, is often considered one of the primary benefits of utilizing React. As a result, it's very difficult to progressively adopt React because, without the entire build-time toolchain, a huge part of what makes React appealing is missing.
Like most issues related to development, I think the question of whether React is better than Vue, or vice versa, is dependent upon the goals and requirements of any given project.
This post discussed some of the pros and cons that I think are associated with each framework. However, both frameworks make it easier to implement interactive user interfaces, so whether one is better than the other probably comes down to a matter of preference, project requirements, and whether their respective ecosystems can support the goals of a given project.
I'm personally a fan of JSX, so I find the developer experience of React very appealing. Also, the introduction of hooks has simplified a lot of code. However, it's obvious to me that from a pragmatic perspective, Vue can be the better alternative in certain scenarios.
Which one will you choose?