React Vs. Vue.js: A Detailed Comparison

Unless you’ve been living under a rock, you’ve probably heard of Facebook’s wildly-popular React JavaScript library for building single-page web application  . You’ve may have also heard of Vue.js, a full-featured utility that can be leveraged for the same purposes. But which one is right for your project?

In this article, we’ll explore some of the differences and similarities between the two. We’ll start with some simple comparison points, then move on to more complex topics.

It’s worth remembering as you read this article that React and Vue are both trying to solve one problem – SPA UI management – in different ways. While both utilities focus on code-reuse through the idea of components, the fundamental thinking behind React and Vue is somewhat different, and each has a unique way in which it addresses the problem of building modern single-page web applications.

(Editor’s note: This article is specific to Vue.js version 2. At the time of this writing, version 3 is in beta and anticipated to be mostly backwards-compatible with code written for Vue 2. The last release for version 2 will be supported for 18 months to give developers time to upgrade to version 3.)

Library vs. Framework

Perhaps the simplest place to start is differentiating between React and Vue by the utilities they provide.

Productivity and Learning Curve

Both React and Vue allow developers to be fairly productive with their utilities after getting over the initial learning curve. Vue provides application routing out-of-the-box, small-scale state management via each component’s own “data” object, and more full-featured state management, achieved with an optional library, Vuex, which is provided and maintained by the Vue core team. By contrast, the React is a JavaScript library that concentrates on providing tools to build declarative user interfaces. It only provides small-scale state management on a per-component basis. Developers will have to either club it with Context API OR integrate third party libraries (like Redux) for a full-featured state management.

The good news is that React’s popularity has prompted the community to develop libraries that are easily integrated into React projects, and documentation (with lots of examples) that lend themselves well to the ongoing growth of the React community is readily available. In other words, the popularity of React makes it more likely that you’ll be able to find examples, blog posts and/or documentation on how to integrate and use a third party library for functionality that React doesn’t provide out-of-the-box. This is a function of popularity that Vue just can’t match right now.

Hold My Hand or Get Out of My Way?

React is more of a library than a framework. It concerns itself with one thing and one thing only: the UI. Handling API calls, routing, and to some extent, state management, are all separate responsibilities that you need to handle on your own through your own implementation or a third party library. React only cares about the user interface itself and nothing else.

This sort of approach is useful for projects and/or teams that want to set everything up in their own specific way and prefer a “just get out of my way and let me work” developer experience. More experienced front-end developers may find this approach preferable to that of a framework that provides integrated libraries, an application generator with predefined directory structure, etc.

By contrast, Vue.js is more of a framework, in that it ships with multiple features that pertain to building single-page applications included and/or available with optionally-used module(s) maintained by the Vue project. API calls are still an external responsibility (Axios is usually a good go-to here), but in general Vue will provide a lot of utility here that React just doesn’t concern itself with.

Code Organization

Vue can provide some directory structure to guide developers in building their project through the CLI application generator. You’re not bound to this structure, however, and can add to it, or modify it, as much as you like. This sort of guidance can be useful for beginners or large teams that need consensus on “where stuff goes”, but may get in the way of experienced developers and/or teams that have their own way of doing things that differs from Vue’s defaults.

While React does have some recommendations on application structure, it doesn’t force one on you. Officially, React has “no opinion” on directory structure; you’re free to set things up however you like. This is in contrast to other frameworks that consider themselves “opinionated” about workflow and do impose specific structure on you (not front-end, but Rails comes to mind here). Experienced developers may find this a refreshing perspective.

Community vs. Corporate Backing

While Vue.js is maintained by a volunteer community, React is fully funded and maintained by Facebook with contributions from the open source community. There are pros and cons to each situation, and neither is a clear “winner” overall.

Funding

On the plus side, corporate funding means several people are paid good money to work on React full time. That’s in sharp contrast to the Vue project, which is partially funded by third parties but relies primarily on community contributions (e.g. vuemastery.com).

While it may sound like React is a clear winner in this category, the truth is more nuanced. With corporate backing comes corporate control. So far, Facebook has been a good steward of the React project, generally doing the right thing for the community, but there is no guarantee it will continue that trend, and can change at any moment for any reason with little to no recourse for the worldwide community beyond a complete fork of the project.

Decision Making Authority

Of particular concern when it comes to corporate backing is the issue of authority. With React, control over the project is rather centralized; there’s less need for consensus from multiple people all over the world, decisions can be made faster and the project’s overall trajectory and direction is focused because of that concentration of authority. This can also be a bad thing, though: a centralized team can make the wrong decisions faster, can more easily ignore community input, and can take the project in a direction that the community disapproves of with little recourse. If that last point were to happen, a project “split” is likely to occur; think of concerns regarding MySQL when Oracle bought Sun Microsystems, and the emergence – and subsequent divergence – of MariaDB since then.

Vue is, by contrast, primarily community driven with some financial contributions from third parties. While it may take longer to make decisions due to the nature of achieving consensus, it’s very unlikely that decisions made by that consensus will be to the detriment of Vue’s developer community.

Contributors and Project Longevity

Lacking complete funding means that contributor turnover is much more likely to occur, leading to potential instability the further up the “chain” that turnover happens. If something were to happen to the Vue’s original creator, for example, what would that mean for the Vue project as a whole? Who approves pull requests? Who administers user permissions on the primary repository? Who ultimately decides the direction of the project? Who decides what goes into a new version release?

React, by contrast, is clearly more stable in this regard; if somebody leaves the React project for any reason, Facebook will just hire or promote from within to fill that vacancy. Problem solved.

Performance

Performance is likely to be top of mind for a lot of developers. Will whatever you build be as fast in Vue as it is in React?

The good news here is that since both Vue and React track changes to a virtual DOM object and conditionally re-render only what changes, performance between the two is roughly on par. Updates to what the user ends up seeing are generally fast and immediate with no major lag introduced by either utility on its own.

If you’re interested in performance differences between the two in detail, Stefan Krause has some extensive benchmarks published on his blog for React, Vue and other frameworks as well. Looking at the data between the latest benchmarked versions of Vue and React, there’s very little tangible difference between performance for the two frameworks; significant differences seem to emerge infrequently, and only with extremely large scale use cases well outside the boundaries of what any human being would find useful (when you’re rendering thousands of rows of data at a time, for example). As such, those differences become nearly pointless for most real-world applications.

One factor to note, however, is that React offers some capability to control the process of re-rendering components via performance optimizations like shouldComponentUpdate(). Vue, by contrast, doesn’t appear to have a similar way to prevent the re-rendering of a component, though there are some methods of Vue performance optimization.

Developer Tools

Both React and Vue have developer tool sets available as browser extensions and standalone desktop applications. React extensions are available for Chrome and Firefox, as well as a standalone app (useful when building things with react-native); Vue developer extensions are also available for Chrome and Firefox; additionally, there’s a standalone Electron app for unsupported browsers/environments.

Security

Security should be given serious consideration at all levels of the stack – including client-side code execution. We’re going to skip discussing security questions about who gets to update what data, because whatever API(s) you’re working with should be enforcing authorization rules as it deems appropriate. What we’re concerned with is front-end security, specifically what we can control in the user’s browser.

Sanitizing User Input

Both Vue and React sanitize evaluated information by default. In React this is done through JSX, and in Vue this happens automatically when using {{ expressions }} in your template code.

While in theory it may be possible to execute JavaScript in one of these contexts, it’s unlikely that an attackers code would escape the sanitization parser, and even if it did, it would need to successfully execute within the context of the evaluated component, accessing objects that may not even exist in that context, in order to pull off any sort of attack.

That said, the key words here are “in theory”; in reality, the probability of this happening is extremely low. The API from which you’re pulling the information to be rendered should also be sanitizing this information before giving it to you through your API call as well, further reducing the probability of an attack along this vector being successful.

(In the aforementioned cases, this is excluding calls to output raw code from an untrusted source. If you’re doing that anywhere, all bets are off.)

Understanding Components

Both React and Vue use the “component” as the underlying, basic foundational element upon which all UI aspects are built. In this context, a component is a collection of HTML with (or without) runtime-evaluated expressions and information that can be re-used as a singular item.

You could think of this as one custom HTML tag being used to replace a bunch of them that would build a portion of the user interface. For example, you could use a <LoginForm /> tag to represent the markup that would otherwise be used to create the login form (<input> elements and so on):

<div>
  <input type=“text” placeholder=“Username”>
</div>

<div>
  <input type=“password” placeholder=“Password”>
</div>

<div>
  <input type=“submit” value=“Login”>
</div>

We could consider the above code a single “LoginForm” component, then render that component via custom HTML tag:

<div>
  <LoginForm />
</div>

Both Vue and React are built around this concept and provide ways of pushing data from the document calling the component into the component itself when it renders. This is to encourage code reusability and simplify the potentially daunting task of building a modern user interface.

Application Routing

Any sufficiently useful application is going to need some kind of routing. React doesn’t have any routing capabilities that ship with React itself, but there is the react-router-dom project which provides a way to handle routes in React.

Using react-router-dom is fairly straightforward, as the video in the aforementioned link will show. In short, you define a place in your application interface to render the result of a component that you tell the router to use. You can configure it to match URL parameters by variable name, such as /myapp/:myVar. It also provides a facility for rendering links in your application.

Vue, on the other hand, provides application routing from the start without needing a third party library. To make use of it, you start by configuring a routes object (in your main application file, or import it as a module from another file) that maps out the name of a route, the relative path to match against (including any named URL parameters, just like the example for react-router-dom above), and the name of the component to render when the route matches. In your primary application template, you’d use a tag named <router-view /> to render the results of the component mapped to that route in your routes object.

A simple example of application routing in Vue.js

Templates/Markup

Vue and React have a very different approach when it comes to building the structure (“markup”) of your components. When it comes to separating logic and markup, both frameworks have issues. Perhaps the benefits provided by using Vue or React outweigh the nontraditional way in which markup is mixed with logic, however.

React and JSX

React utilizes a “flavor” of HTML called “JSX”. This is basically HTML with a few minor tweaks; for example, calling a “class” property on an HTML element, you’d need to rename “class” to “className” because “class” is a reserved word in JavaScript.

It’s worth noting that JSX is not a web standard whatsoever. It has absolutely no use outside of React and is not natively rendered by browsers without JavaScript to parse it into valid markup. Good thing, then, that it’s almost identical to regular HTML with only a few very simple and minor changes for special circumstances.

React’s JSX may be a controversial topic for some because of the way it ends up getting used. Consider the following simple React code sample:

class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}

// Example usage: <ShoppingList name="Mark" />

Note that in this example, we’re creating a class with a render method – nothing out of the ordinary there. But what that render method returns is unusual. Instead of reading a file or HTTP location to get markup data, we inject the markup for the component directly into the render method. This is how you use JSX.

For years, developers have been taught to separate logic from presentation, and for good reason. JSX appears to break this principle, however, and may cause some resistance to adoption among developers for this very reason. It’s more commonly accepted to read an external resource (another file or HTTP location, for example) to retrieve the markup dynamically, then call a render function on that, than it is to pass the markup directly into the logic in such a literal – and non-modular – way.

While you could write React code without JSX, it would be very tedious, requiring you to call “React.createElement” for every DOM element of your component (and every DOM element child of every element), resulting in an unmaintainable mess; this has the end result of making JSX, realistically, a requirement for using React.

An example of using React without JSX, from the reactjs.org tutorial.

Saying you don’t have to use JSX to use React is like saying, “you don’t have to have electricity to live in the modern world.” Sure, that’s technically true, but it’s such a disadvantage and such a pain not to that no one will actually end up doing it.

Regardless of anyone’s feelings about JSX, it’s clear that this approach works, as evidenced by millions of lines of JSX code (and growing) powering all kinds of mission-critical web applications all over the world. While it’s a departure from established development practices, the productivity gains and resulting application quality facilitated by React may outweigh the cognitive dissonance caused by adopting this approach.

Vue.js and Single-File Components

In Vue, we have “templates” that are just regular HTML. The hitch here, however, is that generally these are all bundled up in the same file as the logic and stylesheets for the component. This, similar to JSX, breaks the “separate presentation and logic” rule, albeit in a different way.

Similar to JSX, there’s also the “you don’t have to do it this way” argument. However, in a real world Vue application, you’ll generally see things done this way much more often than not, and departure from this established norm may not be worth the work required to make such a change productive or useful.

An example Vue.js template may look like this (for the whole file):

<!- - src/components/Thing.vue - ->
<template>
<div>
  <p>Hello, {{ name }}!</p>
</div>
</template>

<style scoped>
p {
  font-family: “sans”;
}
</style>

<script>
export default {
  name: ‘Thing’,
  data() {
    return {
      name: ‘Bob’
    }
  }
}
</script>

As you can see in this example, the trend of mixing presentation and logic is alive and well in Vue, and developers may have just as much opposition to using Vue in this way as they would have to React for the way JSX is used. And, just as with JSX, a plethora of running, mission-critical and high-performance application code written in this way proves that this approach clearly works at all kinds of scale.

Vue: Scoped Styles

Perhaps of more interest to some developers – and designers – is the fact that CSS in Vue can be locally scoped to just that component and nowhere else. Consider this Vue file which defines a “view” (which is basically an encapsulating component in Vue to orchestrate the layout of a “screen” by laying out the markup for how other components will be used) consisting of N <ProfileCard /> components:

Scoping styles to a component means that particular CSS affects only that component.
Click to see full size version.

As you can see, in src/views/Home.vue we define h1 as having a 4em font size. Then in src/components/ProfileCard.vue we define h1 again as having a 2.5em font size. So which one gets used: the first, or the redefined version?

In this case, both. Because we’re using scoped on our <style> tag in both components, the CSS generated by Vue for that component is applied only to that component and nothing else.

Source code for the example used here is available at
https://github.com/jahio/vue-component-example.

While you can certainly accomplish this with React using the styled-components library, it’s not quite as easy as just tacking on one word inside a <style> tag.

State Management

Managing the state of objects and data can be a very complex endeavor, especially as project scope grows over time. Both React and Vue provide a built-in way to manage state on a small scale, though it’s not quite appropriate for more complex applications that will eventually hit a larger scale, and should be used judiciously to prevent overcomplication in the long run.

Change the Data, Not the DOM

Both utilities encourage a pattern of development that has you changing data, not the document markup. Both React and Vue have internal “data” objects scoped per-component. You tell your components to output that data via JSX or Vue’s template system, and like magic when that data changes, the rendered document on your screen updates in real time.

This is great for simple “Hello World” applications and similarly small-scale components, but when you build larger applications for real-world use, you’ll have a pretty hard time making use of this alone.

Enter state management. The idea is to provide a codified, formal system of reading, tracking changes, and changing a semi-global data store that only exists for the life of the page in the user’s browser.

When using a state management system, both Vue and React will automatically observe changes to the variables in that state management system and update the DOM in real time (if the component is visible on the screen) when changes are detected.

React: Redux

React doesn’t ship with its own fully-featured state management solution, so you’ll need to bring your own. The most popular option seems to be the Redux library, which provides a framework-agnostic way of handling application state, then allows developers to write bindings to link it up with their framework of choice. Ergo, to make use of Redux in a React project, you’ll actually need to use the react-redux bindings to link the two together.

Once installed and configured, you can use Redux to set default application state, provide methods to change the data, and implement filters on that data, and do all of this in a modular way. There’s a (rather lengthy) tutorial here, and a code sample of what this might look like for a simple “todo” app here.

Vue: Vuex

In Vue, we have the optional Vuex project for managing application state. While it doesn’t ship with Vue itself “out-of-the-box”, you can install it easily with npm. One of the first major differences between Redux and Vuex is that, while Redux is intended to be framework-agnostic with “bindings” to enable its use in other frameworks, Vuex is built and maintained by the Vue.js team, and intended to be used in Vue applications.

Once installed and configured, Vuex provides a way to read and write data to the state management store it provides. You can read data directly if you don’t need to transform it in any way (e.g. filter, sort); otherwise, you can make use of Vue’s computed properties to do things like find() and sort() on that data before displaying it.

Changing Data

Making changes to data, in either state management system, is more complex. One of the most maddening problems you can run into with a large application is figuring out what component changed the state of data. If you have a structure of components all operating on a global store that’s nested several levels deep, you may have no idea how your data got changed or updated.

Enter actions and mutations. To change data in Vuex, you “commit” a mutation to the store. This allows it to track what, specifically, made the change, which – when used with Vue’s developer tools – can help you track down the source of a bug much easier than without this capability.

But you don’t commit those mutations directly because changes to data are synchronous. Mutations themselves can’t be run in an async manner, which is really going to hamper application execution when it’s time to call an external API.

To do this right, you instead want to dispatch an action. Unlike mutations, actions are able to be run asynchronously, and when completed can then commit the needed mutation to change application state.

Vuex and Redux allow you to modularize your application state using different files and namespaces, so you can separate objects according to the components that make use of them. You can define their initial state in these files, and using component lifecycle hooks, update them when the component is “mounted” into the application (for example).

More information on Vuex can be found here, and to see an example of modularized Vuex in use, check out this article’s companion source code. You can find more information about Redux at redux.js.org.

Native Application Development

Using the react-native project, you can build native iOS and Android applications using the React framework. This is a major boon to application developers, since they can simplify their build processes and standardize on a single language instead of having to mix JavaScript, Objective C or Swift, and/or Java in order to ship their app to consumers mobile devices.

“Does Vue have an equivalent project?”, you may be asking. At least two such projects exist: nativescript.org and Vue Native. The NativeScript project purports to build native applications for both Android and iOS directly, while the Vue Native project seems to rely on the react-native project at some level, either through the Expo library or by relying on react-native directly.

While react-native is certainly the 800 pound gorilla in the room, NativeScript and Vue Native provide interesting and viable alternatives to accomplish the goal of building a native mobile application using Vue.js.

So Which Should I Choose?

When considering which of these venerable utilities is right for your next project, consider yourself, the project, its stakeholders, and the team you’ll be working with. How tolerant are team members likely to be with a learning curve? Do you have existing expertise in one or the other? Is this a proof-of-concept built just to get to the next stage of funding, or is it intended to be a primary app used by millions? How senior are you and the others in your team when it comes to JavaScript and front-end development in general? Do you have concerns over the longevity of React or Vue given each project’s unique position pertaining to its governance?

There’s no hard-and-fast rule that lends itself to simple, prescriptive recommendations here. While React may be more popular and Vue may provide more included functionality and structure, both are excellent choices for building single-page applications, both perform very well, and both have bright futures.

At some point you just have to pick one and go.

The author would like to thank Sahil Bhatia for his contributions in writing this article.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.