Journey from React 15 to React 16

Akash Verma
4 min readMar 26, 2018

--

I work for Evive, a healthcare benefits start up. The frontend team of the company was tasked with migrating the company’s product from jQuery to React. When we started the project in July, React 15 was the latest version available and the time we finished re-writing the web application React 16 was already released. Moving to React 16 required additional time and as always we had time constraint. We released the product as per the deadline in React 15 and simultaneously initiated a discussion to migrate to React 16.

We were lucky that the management agreed to this but we could have been asked “Is it really required to migrate? “ and rightly so.

There could be two reasons when you want to be updated with the latest version:

  1. You always want your stack to be up to date.
  2. The latest release has features which is going to improve the user experience and performance of your application.

With React it was the second point. Let us the quickly go over the features that made us to upgrade.

Error Boundary

One of the features that got me excited is better error handling. Previously, runtime errors during rendering could put React in a broken state. With React 16, instead of unmounting the whole app every time there’s an error, you can use error boundaries. Error boundaries are analogous to try{ }catch(e){ } statements, but live inside and are scoped by component hierarchy instead of inside a given block of synchronous javascript.

As per React docs, 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 component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them. A class component becomes an error boundary if it defines a new lifecycle method called componentDidCatch(error, info)

class AppErrorBoundary extends Component {
static propTypes = {
children: PropTypes.node,
errorMessage: PropTypes.string,
};

static defaultProps = {
children: <div />,
errorMessage: 'We encountered an error'
};

state = {
hasError: false,
};

componentDidCatch(error, info) {
this.setState({
hasError: true,
});
}

render() {
if (this.state.hasError) {
return (
<p>{this.props.errorMessage}</p>
);
}
return this.props.children;
}
}

export default AppErrorBoundary;

On the component side you need to wrap your component inside error boundary to make it catch the errors inside your component.

<AppErrorBoundary>
<Component /> // AppErrorBoundary will catch errors of Component
</AppErrorBoundary>

Fragments

React 16.0 added support for returning an array of elements from a component’s render . Instead of wrapping the children in a DOM element, you can put them into an array. This prevents adding additional div or span in DOM from each component that returns multiple element.

render() {
return [
"Some text.",
<h2 key="heading-1">A heading</h2>,
"More text.",
<h2 key="heading-2">Another heading</h2>,
"Even more text."
];
}

With React 16.2 the biggest addition is improved support for returning multiple children from a component’s render method. The feature is called Fragments. Fragments look like empty JSX tags. They let you group a list of children without adding extra nodes to the DOM:

render() {
return (
<>
<ChildA />
<ChildB />
<ChildC />
</>
);
}

Portals

Render items into a new DOM node. A typical use case for portals is when a parent component has an overflow: hidden or z-index style, but you need the child to visually “break out” of its container. For example, dialogs and tooltips. The main advantage is it follows event delegation as per your React tree node even though it is part of a different node.

render() {
// React does *not* create a new div. It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode
);
}

Reduced File Size:

Despite all these additions, React v16.0 is actually smaller compared to 15.6.1!

  • react is 5.3 kb (2.2 kb gzipped), down from 20.7 kb (6.9 kb gzipped).
  • react-dom is 103.7 kb (32.6 kb gzipped), down from 141 kb (42.9 kb gzipped).
  • react + react-dom is 109 kb (34.8 kb gzipped), down from 161.7 kb (49.8 kb gzipped).

That amounts to a combined 32% size decrease compared to the previous version (30% post-gzip).

These are some of the features that made us to upgrade to React 16.

While migrating the application we followed the below approach to have a smooth migration process:

  • Move to prop-types package from React.PropTypes. You can use the Facebook codemod to move or do it manually if this is not a big change.
  • Upgrading dependencies is one tedious task. The console will keep warning you about packages that call React.PropTypes or use React.createClass. You will need to upgrade these if possible, replace or work around them if necessary, or fork and fix them if the package seems unmaintained. This can be really annoying.
  • The private API’s need to be replaced. The ones from react/lib/* .Some of these have been moved to external libraries (the ‘react-addons-’ family of packages) but in some cases, they are just gone. You may need to replace such packages with the existing similar packages.

The above approach worked for us. You may need to follow additional steps depending on your codebase.

Future of React

At a JavaScript conference in Iceland, JSConf 2018, Dan Abramov from the Facebook team announced two improvements, Time Slice and Suspense coming to React by the end of this year. These two improvements are together called Async Rendering in React. It will be part of React 17 release mostly.

--

--

Akash Verma

JavaScript Enthusiast, Software Engineer @goevive. Follow me on twitter @Akash940