Never miss an article about web development, JavaScript and self-growth.

Take Part

What's new in React 16?

There is a high likelihood that there are already a multitude of articles about the new React.js 16 release. But for learning about the changes of the library myself, I wanted to read up all the new React 16 features and improvements too. I thought it would be useful if I would share briefly what I have learned along the way. In the next days, I hope to find the time to update my articles and books accordingly to the React 16 changes.

Less DOM Nodes, because of Fragments and Strings

React 16 supports new render return types. Now you are able to return fragments and strings. What are fragments in React? Before you had to wrap sibling elements into one group of elements by wrapping them into one parent element in order to return them in a component:

Still you would have to use the key attribute to make it easier for React to identify your elements in a list of elements. Although the maintainers behind React already discuss to remove the keys for static content. By returning those fragments, it becomes simple to place a group of elements next to each other without the need to add intermediate parent elements:

The other new return type is the string. Now it is valid to return a string value in a component without wrapping it into a span or div tag.

constGreeting=({username})=>`Hello ${username}`

Both new return types reduce the size of intermediate DOM nodes we were used to use before.

There are Portals in React!

React 16 has portals now. They are a way to render elements outside of the component where the portal is created. The portal only needs to know about a DOM node in your application where it should render the given elements.

In your application, you would only need a DOM element with the id attribute “modal”. Afterward, the Modal component would be rendered outside of the App component. Portals give you a hook into the outside HTML.

What are the use cases for Portals? One pain point prior React 16 was it to render modals. Often a modal was deeply nested in the component tree, because it was opened and closed in one of these components, even though, from a hierarchical DOM node point of view, the modal should be at a top level of your component tree. Because of this constraint, developers often had to apply CSS styles to make the modal float above the remaining application even though it was deeply nested in the component tree. Thus portals came along in React 16 to enable developers to render elements, in this case a modal, somewhere else, in this case up at a top layer component level. Still, it would be possible to control the model from a deeply nested component by passing the proper props to it and by opening and closing it.

React's new Error Boundaries

There is a new lifecycle method in React: componentDidCatch. It allows you to perform error handling for your React components. In the lifecycle method you get access to the info and error object: componentDidCatch(error, info).

Let’s see it in action. Imagine a component that shows and updates your user account:

What happens when you would reset the user object? Consider a case where you would want to update your user object in your backend by doing an API request but by accident you set the whole user object to null in the local state of your React component. You can simulate it by using a button that resets your user object in React’s local state to null.

You would get an error message saying: “Cannot read property ‘username’ of null”. The whole application crashes because the username property is destructured from the user object. By using componentDidCatch you can prevent it and display a proper error message when an error is caught in your render method. You can use the componentDidCatch lifecycle method directly in your Account component. However, a nicer way to keep it reusable and maintainable in your application would be to introduce a so called error boundary.

That way, you can use it for your Account component but for every other component too:

constApp=()=><div><MyErrorBoundary><Account/></MyErrorBoundary></div>

When you reset your user object by accident now, the error message should be visible instead of the Account component and instead of crashing your whole application. By using error boundaries, you can keep your component error handling in React at strategic places. Don’t clutter your whole component tree with error boundaries, but place them at important places where it would make sense to replace a component or a subset of components with an error message.

When you are in development mode, the error boundary is only visible for a couple of seconds. Afterward, you will see the real error for developing purposes. In production mode, it will keep showing the rendered output of the error boundary though. In order to mimic a production build with create-react-app, you can install pushstate-server on the command line, build your application and serve it with pushstate-server on localhost:9000:

npminstall-gpushstate-servernpmrunbuildpushstate-serverbuild

There is one more important fact for error handling in React components. The new lifecycle method componentDidCatch gives you a great way to send your error reports to your favorite error tracking API. Personally, I use Sentry to push all my occurring errors to one centralized service.

Return null in React's setState

There are two ways in React’s local state to update the state with this.setState. The first way of doing it is using an object:

const{counter}=this.state;this.setState({counter:counter+1});

Due to this.setState being executed asynchronously, you would want to update your local state with the second way by using a function instead of an object:

this.setState(prevState=>({counter:prevState.counter+1}));

Now you wouldn’t run into any stale state in between when computing your new state. But that’s not the change for React 16. In React 16, you can return null in your this.setState function to prevent updates. Before you had to check a condition outside of your this.setState block:

That way, you operate again on the current state at the time of the execution, because this.setState is executed asynchronously. If your condition depends on the current state, it can become important to have access to it in this.setState and to be able to abort the update.