Vue vs React: 2018 Edition

#

Just over a year ago I wrote a 🔥-y piece comparing Vue.js vs React. Today, the argument about these two JavaScript frameworks is as alive as ever, but over the last year much has changed. I figured it was time I took another look at these behemoths, so let’s dive in!

The Contenders

To recap: React and Vue are both popular JavaScript frameworks for building interactive applications. React is backed and used by Facebook – Vue isn’t backed by a corporation but is very popular in the open source community.

In my previous article I created two sample apps to highlight the differences and similarities between React and Vue.

When we asked you what you thought last year, #TeamVue narrowly won, but perhaps things have changed and #TeamReact will take the framework crown this year:

Updating React

Since the last article was published, React 16 was released. The current version of React is 16.4 so I thought I’d see what it would take to update my sample app.

React 16.4 has a lot of improvements, including the ability to return string fragments, better error handling and a new context API.

My sample app (Pasta Pete React) uses Create React App, so thankfully, upgrading was a breeze! To upgrade everything all that I needed to do was the following:

yarn upgrade --latest react react-dom react-bootstrap react-scripts

Now that we’ve got the latest version of React, let’s see what some of these new features can do.

Render Return Types

One of my favorite updates in React 16 is that you don’t have to wrap items in your render functions any more! For example, now you can do things like this:

class Wat extends Component {
    render() {
        return (
            'Ya man! 🦄'
        );
    }
}

In the past, the ‘Ya man! 🦄’ string would need to be wrapped in a <span> tag or similar. Sweet.

You can also return a list of items without wrapping them in an extra tag. This is thanks to React’s new fragments feature. Basically you can wrap a list of elements with <></> and voila!

class Wat extends Component {
    render() {
        return (
            <>
            <p>Bugs: Ehhhhh, what's up doc?</p>
            <p>Fudd: Quiet WABBIT!?!</p>
            --hilarity ensues--
            </>
        );
    }
}

One caveat, this syntactic sugar isn’t available without Babel 7 which is currently in beta. No worries though. You can use the next branch of react-scripts and do some yarn shenanigans 🙄.

The required yarn shenanigans:

  • run rm -rf ~/.nvm/versions/node/v9.2.0/bin/eslint
  • remove eslint from package.json
  • delete the yarn.lock file
  • run yarn
  • Profit?

Error Handling

One of the things that always bothered me about React was its cryptic errors. Even when using Gutenberg’s development versions I would frequently run into fun React error messages that made no sense.

React 16 has better error handling and more correctly reports the specific error that occurred in the console. In addition to that, there is a new error boundary component that is super helpful for catching errors. It allows you to return a nicely formatted message if/when an error occurs. Cool!

In your app you can use the componentDidCatch() lifecycle method to handle errors and then in your component you can handle errors like so:

<ErrorBoundary>
    <MyWidget />
</ErrorBoundary>

Context API

Another thing that irked me in the past was how you’re supposed to ‘lift state up’ to the highest level and pass data as properties to child elements. This gets pretty unwieldy if you have multiple levels of nested components.

React’s new Context API is pretty cool if you’ve got complex props that you need to pass down multiple levels of child elements.

For example you can now use the Component.Provider syntax to provide data to all child components and the Component.Consumer syntax to consume the data from any level of parent.

Registering a provider is pretty simple, you just provide a default for the value property:

render() {
    return (
        <PastaContext.Provider value={this.props.spicyness}>
            <SpiceButton changeSpice={this.props.toggleSpicyness} />
        </ PastaContext.Provider>
    );
}

Then, inside the <SpiceButton /> component we have the following:

    <PastaContext.Consumer>
        {spice => (
            <button onClick={props.changeSpice} style={{ backgroundColor: spice.background }}>
                Change Spicyness
             </button>
        )}
    </PastaContext.Consumer>

The spice argument is the value passed from the provider. Note that it’s not passed via a prop, as usual. Neat!

In the past you’d have to go full Redux, but with the Context API you have another option if you’re app isn’t too complex.

Updating Vue

Ok so we’ve seen some of the new stuff that’s been added to React in the past year, but what has the Vue team been up to and how does it compare to the updates React has gotten?

Vue CLI v3

The first thing I noticed is that there’s a new Vue CLI tool to create a pre-configured Vue app. It’s actually really cool because it also provides a UI to set up a new project!

Vue CLI GUI

However, as with my process with React and Babel 7, Vue CLI 3 is still in beta, so…there’s some hoops to jump through to upgrade an existing project. Let the fun begin!

Luckily there’s not much to it, though it is a bit more scorched earth than with Create React App. I basically just created a new app with Vue CLI 3 and copied over my /src and /tests folder as outlined in this forum post.

However, once upgraded, we’re now up and running with all the latest Vue coolness!

Vue CLI 3 is a major update and I’d argue is better than Create React App. It allows you to select Vuex (Vue’s version of Redux) during the creation step, as well as unit/e2e testing, typescript and a bunch of other options.

This also really trims down your package.json file by using a plugin-based architecture. You no longer have to go looking for a Webpack plugin whenever you need a package. Just run vue add router if you want vue-router.

Error Boundaries

Similar to React’s improved error handling, Vue 2.5 included an improved errorCaptured hook.

Vue already had a global config.errorHandler, but no granular error handling for specific errors that get thrown in child components. This update fixes this.

<error-boundary>
    <another-component/>
</error-boundary>

Context API

As far as I can tell there is no equivalent in Vue for React’s Context API. That’s not too surprising because Vuex largely provides similar functionality with a ‘store pattern’ making shared state a bit easier for simpler applications.

SSR

OK so we’ve seen what’s been updated in the React and Vue world over this past year or so, but is there anything else to compare between these two juggernauts?

One thing I did notice while reading through the changelogs for Vue is that a lot of bug fixes and improvements were related to server side rendering (SSR).

Say what now?

Server side rendering is pretty nifty. You’re still running a JavaScript app, but doing the template rendering and routing on the server. Most commonly this is done with Node JS, so it’s all JavaScript on the front-end and back-end.

The reason you’d want to use SSR is that a typical single page app contains an empty HTML file with your framework of choice rendering components and content to the empty HTML page.

This isn’t great for search engines or screen readers because if you’re just viewing the HTML source you won’t get too much information. Because of this, some smart people decided to make React and Vue work on a server.

With SSR, templates are rendered on the server with front-end interactivity handled by the JavaScript framework.

Vue seems to take SSR a bit more seriously as they’ve got a great guide in their documentation, a community-built SSR library – Nuxt.js, and provide docs on how to render Vue templates with PHP! In reality though, it’s basically a server rendering your JS templates to HTML, and setting up state management (if you’re using it) and routing on the server.

React Native vs. NativeScript

In my last post I mentioned that Vue didn’t have an answer to React Native. While this is still true for the Vue core project, another project called NativeScript has filled this void. NativeScript reportedly lets you write Vue and Angular 2 apps that will be compiled to native applications. This is true for both Android and iOS.

I’ve only quickly played around with the NativeScript playground but it looks promising. Hard to believe you can now write cross-platform mobile apps with Vue, Angular and React! What a time to be alive!

via GIPHY

The Winner(s)

A lot has changed in the past year with both React and Vue. My personal opinion is that both frameworks are incredibly full-featured and would work well for most developers. There are really no major drawbacks between Vue and React, it more boils down which approach you prefer.

React is still more JavaScript-y in how you render components and pass properties around. You’re definitely more decoupled from your templates.

Vue is still template and attribute based and is probably a better choice if you’re looking to integrate a new framework into an existing JavaScript application.

I personally still favor React because I know it better, but I could get used to Vue. As usual I’ll ask, what do you think? Vue fan or React fan? Let us know in the comments!

About the Author

Peter Tasker

Peter is a PHP and JavaScript developer from Ottawa, Ontario, Canada. In a previous life he worked for marketing and public relations agencies. Love's WordPress, dislikes FTP.