Rethinking with React 16

Rethinking with React 16

Written by Vivek Nayyar and edited by Tierney Cyren

With React 16, we saw the release of React Fiber–a long-awaited update to React itself. With React 16 which is built on top of a new core architecture, codenamed “Fiber”, a bunch of new features have been released to enhance the experience for React developers.

React v16.0 comes with some major changes and an update to the react core algorithm. With React v16.0 Facebook has completely revised the internals of React while keeping the public API essentially the same.

Perhaps one of the most exciting area the React team is working on is “async rendering”–a strategy for cooperatively scheduling rendering work by periodically yielding execution to the browser. In order to rethink your existing application in React 16, we need to first understand the changes which have been incorporated into this new release and then we can approach the problems of React 15 and how this release solves them.

React Fiber is a complete rewrite of the React’s reconciliation algorithm. With React Fiber, the new reconciler will have the ability to do the following:

  • Split interruptible work into chunks.
  • Pause work and come back to it later.
  • Reuse previously completed work.
  • Abort work. To learn more about how this new reconciliation algorithm and the fiber architecture, I would highly recommend reading React Fiber Architecture and watching “A Cartoon Intro to Fiber” by Lin Clark both of which are excellent resources to understand the algorithm.

But as Dan Abramov quoted in one of his tweets where he mentions that React 16 enables asynchronous rendering is a myth and the reality is that the React team is still working on that, and it will be opt in when it’s ready.

For now React 16 runs in compatibility mode that for the most part is equivalent to how React 15 scheduled rendering.


Rewriting with React 16

So far, we’ve been working on understanding the algorithm rewrite and the new architecture, going ahead we’ll discuss the various issues which developers were faced with while using React 15, and how React 16.2 solves them. The following new features were introduced in the latest React release:

  • Improved Support for fragments

With fragments we can returning multiple children from a component’s render method.Fragments look like empty JSX tags. They let you group a list of children without adding extra nodes to the DOM: Problems with Earlier React versions:


Problem No 1:

Adjacent JSX Tags should be wrapped with another parent element.

    render() {
      return (
        <button
          radius="4"
          className="couponBtn"
        >
          <span> Apply </span>
        </button>
        <span className="fieldWrapper">
         Buy Tickets
        </span>
     )
    }

This would lead to the following error:

Imgur

Solution: Using React Fragments

    import React, { Fragment }  from "react";
    render() {
      return (
        <Fragment>
          <button
            radius="4"
            className="couponBtn"
          >
            <span> Apply </span>
          </button>
          <span className="fieldWrapper">
           Buy Tickets
          </span>
       </Fragment>
     )
    }

Babel transpiled output for fragment would be:

    React.createElement(Fragment, null, React.createElement("button", {
          radius: "4",
          className: "couponBtn"
        }, React.createElement("span", null, " Apply ")), React.createElement("span", {
          className: "fieldWrapper"
        }, "Buy Tickets"));

Problem No: 2

JavaScript errors inside components used to corrupt React’s internal state and cause it to emit cryptic errors on next renders.

Solution: Use__Error Boundaries

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the crashed component tree.

A class component becomes an error boundary if it defines a new lifecycle method called componentDidCatch(error, info).

With error boundaries, even if one of your component’s results in an error, the entire react app would not get unmounted and instead only the erroneous component would display a fallback UI and the entire app would still be fully functional.

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
      componentDidCatch(error, info) {
        // Display fallback UI
        this.setState({ hasError: true });
        // You can also log the error to an error reporting service
        logErrorToMyService(error, info);
      }
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }
    <ErrorBoundary>
      <MyWidget />
    </ErrorBoundary>

Some examples of Error Boundaries:

Imgur

Erroneous product card in an e-commerce category page

Imgur

Messenger using Error Boundaries

I've written a similar article explaining error boundaries, please refer to it for detailed info on error boundaries and the use cases.


Problem No 3:

Custom DOM Attributes

    <div boxname="test" />
    // will be displayed in React 15 as:
    <div />

Solution: With React 16, unknown attributes will be passed onto the DOM.

    <div boxname="test" />
    // will be displayed in React 16 as:
    <div boxname="test" />


Problem No 4:

Server side rendering being slower with React 15

This is how we used to do SSR With React 15:

    // using Express
    import { renderToString } from "react-dom/server"
    import MyPage from "./MyPage"
    app.get("/", (req, res) => {
      res.write("<!DOCTYPE html><html><head><title>My Page</title></head><body>");
      res.write("<div id='content'>");  
      res.write(renderToString(<MyPage/>));
      res.write("</div></body></html>");
      res.end();
    });

Then, in our client bootstrap code,we tell the client-side renderer to “rehydrate” the server-generated HTML using render(), the same method we would use in a client-side rendered app:

    import { render } from "react-dom"
    import MyPage from "./MyPage"
    render(<MyPage/>, document.getElementById("content"));

Solution: In React 16, there are two different methods for rendering on the client side, render() and hydrate(). render() as we already know for rendering content solely on the client side, hydrate() for rendering on top of server-side rendered markup.

Furthermore, React 16 is better at hydrating server-rendered HTML once it reaches the client. It no longer requires the initial render to exactly match the result from the server. Instead, it will attempt to reuse as much of the existing DOM as possible.

The same code snippet with React 16 would be:

    import { hydrate } from "react-dom"
    import MyPage from "./MyPage"
    hydrate(<MyPage/>, document.getElementById("content"));

React 16 SSR works faster because:

  • React 16 Generates More Efficient HTML
  • In React 15, each HTML element in an SSR document has a data-reactid attribute, whose value consists of a monotonically increasing ID, and text nodes are sometimes surrounded by comments with react-text and an ID. In React 16, however, all of the IDs have been removed from the markup, so the HTML for that same snippet is considerably simpler.
  • React 16 Performs Less Strict Client-Side Checking
  • React 16 Doesn’t Need To Be Compiled For Best Performance

Imgur

  • React 16 Supports Streaming
  • 2 New APIs : renderToNodeStream and renderToStaticNodeStream

Imgur

  • Reduced File Size

Imgur

React 15 bundle size Imgur

React 16.2.0 bundle size


Real World Examples of performance improvement with react 16

There has been a lot of performance observation and testing done by apps that have made the upgrade to ReactJS 16.


MIT Licensed:

React v16.0 is available under the MIT license. They’ve also published React 15.6.2 under MIT.


Conclusion

It’s definitely worth upgrading and optimizing your current React App given the performance benefits, especially if you want to build performant web apps. You’ll see an improvement from the version upgrade alone. I hope this article will help you achieve a bit more understanding of the new features introduced in React 16 and how async rendering and this new reconciliation algorithm works. With all these performance benefits and with these new features, we should all start rethinking our apps with React 16.

Resources

For further reading, please refer to the following links:

Rapid Prototyping Javascript and Hardware

Rapid Prototyping Javascript and Hardware

Writing JS apps for Fitbit Ionic

Writing JS apps for Fitbit Ionic