So with React 16 we have all new internals (codenamed Fiber) whilst retaining the API we all know and love. It's pretty incredible that the React team have managed to pull this off as it gives us a framework geared towards the future without the current development community having to re-learn a whole new set of API's.

Whilst its possible to delve deep into the technical marvels of what Fiber will enable going forward in terms of cool performance benefits, there are some really cool and helpful improvements that will make our lives easier right from day one of using V16+.

1. Error boundaries

So in the past, if an error was thrown whilst React was rendering then the UI would still render in a corrupted state that might require a refresh in order to allow the application to function correctly with only some potentially cryptic console errors to help you deduce what went wrong and when.

Now if an error occurs at this point the entire component tree will fail to mount. This is good in that errors will now need to be handled explicitly otherwise an error in the rendering process could result in the entire component tree not rendering. Fortunately, the React team are not mercilessly harsh so they have introduced a mechanism to allow us to deal with errors in a more maintainable and scalable manner. Enter Error Boundaries.

ComponentDidCatch

There is a new lifecycle method that is at the heart of the creation of error boundaries and that is the new ComponentDidCatch method.

Any error in a component that occurs whilst rendering will bubble upwards in the component tree until it finds a component that implements the ComponentDidCatch function.

So what benefits does this bring

Explicit Fallback UI

So Error boundaries allow you to detect and handle errors during the rendering process gracefully by either rendering the children of the error boundary or a fallback UI.

render() { if (this.state.hasError) { return <div>Sorry, there was an error.</div>; } else { return this.props.children; }
}

As the default behavior has now changed to display nothing if an error occurs during rendering we will now have no choice but to explicitly offer a fallback UI.

Richer error reporting

So in the code sample above we can see that the componentDidCatch function has the following signature

componentDidCatch(error, info) {
//code to handle error
}

As well as the standard error the new Fiber architecture enables us to inspect the chain of components that were involved in the caught error.

{ componentStack: "↵ in Profile↵ in MyErrorBoundary↵ in div↵ in App" }

The componentStack property that is given in the info argument gives us an accurate reflection where the error occurred relative to the root of our app.

Easy to understand, declarative error handling

By virtue of the fact we are able to have a component that can take on the role of an Error Boundary for all of its child components, we are able to handle our error handling in a declarative manner by expressing it in our JSX. This makes it much easier to determine where errors will be handled than having to look in each component class in the component tree for an implementation of componentDidCatch.

The new lifecycle hook will trigger for:

  1. Errors in the render function of class components

  2. Errors in function components

  3. Errors in constructors.

  4. Lifecycle methods

  5. Set state

But not, however, errors in event handlers except if the error occurs within a call to the functional version of setState.

2. Common sense rendering improvements

Fragments - No need to Wrap component markup in a parent element

Not having to wrap your element in a container element to ensure every component returns one root element may seem like a simple convenience feature but it actually opens up a whole new set of possibilities.

We can now have components that return collections of things such as list items or table rows effectively allowing us to stack such components to compose the contents of a list or table.

In the example above we are using an unordered list to ensure that a series of values on a receipt are all stacked as all of these figures are based on the same collection of transactions and all belong together.

However, the logic for displaying some of the elements of our unordered list is very different. Fragments let us compose our UI elements so that they are laid out using the same parent element but can be broken up into components that reflect the different information we wish to display, given the data we pass to our components.

So our first fragment takes our transactions and displays each item. The next fragment shows our sales tax. And the final fragment displays the total of all items including sales tax. Composed together they form a sales receipt.

Strings

Components can now also return strings, which allows us to handle tasks such as the formatting of dates and text using declarative components in a manner that is really in tune with the way in which React is built to be used.

All in all Fragments and string components allow us to remove a lot of imperative code from our render functions making it easier to follow the transformation of the data that drive the UI into the elements that the end user sees.

3. Portals

This is a really cool feature that allows us to target and render components outwith our current state tree.

Without thinking through a couple of real-world use cases it might be easy to dismiss this one out of hand. However, in frontend development, there are situations where we want to control or affect elements that are not our main applications DOM hierarchy, such as modals dialogues, overlays, and chat widgets. This provides a really clean mechanism for doing this.

4. SetState of null to avoid rendering

It's pretty common to want to avoid rendering a component and its children when the data that drives the component has not changed.

This is what the shouldComponentUpdate lifecycle hook and React.PureComponent are for.

However, there are times where we do not want to or are unable to change the code within the component that we do not wish to re-render.

If the setState function of the parent component is called with a value of null then this will now prevent an update of the child components being triggered.

Now, there are a few ways of achieving the same result but this one is definitely a great option to have in any function that updates the state.

5. The licensing is a lot simpler

So this one is not really for the guys in the trenches but may help to deal with any reservations from the powers that be about actually using React.

There was a lot of fear and apprehension around the BSD + Patents license. Primarily because Facebook held the copyright for React but would be really nice folks and let you and your company use it, provided you were nice to them. So if you weren't nice to them by say suing them for patent infringement they would have the right to revoke your right to see and use anything that was their code would be revoked!

Now React 16 (and React 15.6.2) have a far more permissive MIT license. So one less reason to overcome on your quest to use one of the hip new frontend frameworks. ;-)

There are some nice performance tweaks and API enhancements to server-side rendering. If you want to read more this article from Sasha Aickin has a great breakdown of the changes as of version 16.

Final thoughts

Now there are a ton of great features not covered here. The ones I have chosen really just make the nuts and bolts stuff simpler to achieve. None of them are earth-shattering in their own right, but at the same time, they make decisions on how to do things in an elegant manner easier and help to make the implementation of commonly occurring problems far simpler. This is at the heart and sole of what React offers I feel. It makes the process of creating highly dynamic and complex user interfaces simpler and that is what all of these features do for you in the end.