Nathan Sebhastian A senior software developer with experience in building full stack JavaScript app with React and Express https://sebhastian.com

What’s new in React 16.9: Profiler API, bug fixes, and more

4 min read 1262

What's New In React 16.9

When the results of the “State of JavaScript 2018” survey were published, React emerged as the winner for the front-end framework category, with a 91 percent satisfaction rate and more than 16,000 users:

React Popularity In The State Of JavaScript 2018 Survey
Sourced from the “State of JavaScript 2018” survey.

React is today’s most popular library for building user interfaces, and in this post, we will look at notable new features, deprecations, and bug fixes that have been added to version 16.9.

The Profiler API

React Profiler was first added to React DevTools in v16.5. This feature measures each component that’s rendered in order to find the “cost” of rendering, so that you can identify performance bottlenecks in React application faster.

In order to use it, you can open React’s DevTools, run a record, render some React components, and then stop the recording.

React Profiler In The DevTools
React Profiler in the DevTools.

The Profiler is useful but a bit cumbersome. You have to start the record and stop it, and then inspect parts of the record that seems to have a high load time. That’s why we now have the <React.Profiler> component, which can be used to gather performance metrics in a programmatic way.

The component will require two properties: an id property and an onRender property. It will fire anytime a component within the tree re-renders. Here is some example code:

import React, {Profiler} from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <Profiler id="MyAwesomeApp" onRender={onRender}>
    <Router>
      <App />
    </Router>
  </Profiler>,
  document.getElementById("root")
);

function onRender(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime,
  interactions
) 
{
  console.log(id)
  console.log(phase)
  console.log(actualDuration)
  console.log(baseDuration)
  console.log(startTime)
  console.log(commitTime)
  console.log(interactions)
}

And here is the result in the console:

Profiler API Results In The Console

While the Profiler from the DevTools records all of your React app, with the <React.Profiler> component, you can isolate and record only the parts of the tree that require more attention. Also, it’s disabled automatically in production build, so you don’t need to remove it after measuring.

For more details on the Profiler component and explanations for its parameters, check out the official documentation here.

Asynchronous act() function

React introduced a testing utility called act() to help developers create UI tests. When writing UI tests, there are tasks like rendering, user interaction events like a click, or data fetching that can be considered “units” of interaction with your React application.

Due to the asynchronous nature of JavaScript, React might actually skip some task and assert the test immediately without waiting until the tasks are done.

React provides a helper called act() that will ensure all updates related to these “units” have been processed and applied to the DOM before you make any assertions.

But a problem with act() was that it could only support synchronous functions, so if you had async functions inside your act(), you were out of luck.

Fortunately, it has now been improved and you can use async/await with act():

await act(async () => {
  // ...
});

This will help you ensure asynchronous updates are done before assertion. Here’s a great tutorial on how you might use act().

Unsafe lifecycle methods are renamed

The React team had already announced this change almost a year ago. In this version, the unsafe lifecycle methods are finally getting renamed:

  • componentWillMountUNSAFE_componentWillMount
  • componentWillReceivePropsUNSAFE_componentWillReceiveProps
  • componentWillUpdateUNSAFE_componentWillUpdate

Don’t worry, unsafe doesn’t mean your app is more prone to being hacked — it simply reminds you that code inside these lifecycles are more likely to have bugs in future versions of React. Check out the details here.

The method name without UNSAFE_ prefix will continue to work in this version, but they are about to be removed completely later, when React version 17 is released. If you open your developer console, you will receive a warning about this:

Unsafe Method Prefix Warning In Console

These prefixed method names are meant to help components with problematic patterns stand out during code review and debugging sessions. It is commonly not recommended to use these methods, so you can discourage your team from using them even more the Strict Mode.

And if your app actually uses a lot of these methods, you can use this codemod to refactor it faster than manually editing them yourself:

cd your_project
npx react-codemod rename-unsafe-lifecycles

It will start an interactive prompt to select which files you want to rename.

javascript: URLs on schedule for removal

Using javascript: inside the href attribute was popular way back when, but today, it is an obsolete practice that can open security holes in your app. It’s easy to accidentally include unsanitized outputs. For example:

const userProfile = {
  website: "javascript: alert('you got hacked')",
};
<a href={userProfile.website}>Profile</a>

The code above will cause an error in React 17, and if you want to run a script when a link is clicked, you need to use the React onClick event handler and a button element that is styled as a link. It is safe and just as easy to implement:

awesomeFunction = () => console.log("Here is javascript: URL alternative!");
// the button below used Bootstrap styling...
<button className="btn btn-link" onClick={this.awesomeFunction}>Profile</button>

Deprecating the FactoryComponent pattern

This is a rather obscure code pattern that was introduced by the React team before compiling classes with Babel became popular. It’s a component that returns an object with a render method:

function FactoryComponent() {
  return { render() { return <div />; } }
}

The syntax looks pretty bad, and since Babel has become the standard compiler for React apps, this component pattern is no longer needed. Supporting it causes React to be slightly larger and slower than necessary. It will be completely removed in a future major release.

If your app happens to use this pattern, you can use FactoryComponent.prototype = React.Component.prototype to keep it working, but it’s far better to just convert the code to a function or a class.

setState loop from useEffect logs an error

An infinite loop caused by setState in useEffect will now log an error, similar to the error you see when you call setState in componentDidUpdate in a class component. Here is some sample code:

function App() {
  const [counter, setCounter] = React.useState(0);
  React.useEffect(() => {
    setCounter(counter + 1);
  })
  return <h1>Watch out infinite loop in the console!</h1>
}

Since there is no second argument that this effect depends on for update, it will run forever until you close the browser window.

Fix Suspense crash when findDOMNode() is called

The <React.Suspense> component is used for lazy-loading components that are not needed in the initial render. But since version 16.7, many developers started receiving the error Invariant Violation: Unable to find node on an unmounted component when using it.

After inspection, developers figured out the error is caused by calling ReactDOM.findDOMNode() inside Suspense. The crash is now fixed in this release, but if you’re still interested, here is a codesandbox to test the error. Just randomly click on the menu until the error appears.

You might not use findDomNode() directly, but this function is actually used in many libraries, like Semantic UI and Ant Design. So you might just unintentionally trigger this bug if you don’t update your React library!

React v16.9 is already available from npm

To update your application, simply run:

npm install --save react@^16.9.0 react-dom@^16.9.0

Or, if you’re using Yarn:

yarn add react@^16.9.0 react-dom@^16.9.0

Happy hacking!

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, tracking slow network requests and component load time, try LogRocket. https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors performance of your app with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps - .

Nathan Sebhastian A senior software developer with experience in building full stack JavaScript app with React and Express https://sebhastian.com

Leave a Reply