DEV Community

Cover image for What’s new in React 16.9: Profiler API, bug fixes, and more
Brian Neville-O'Neill
Brian Neville-O'Neill

Posted on • Originally published at blog.logrocket.com on

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

Written by Nathan Sebhastian✏️

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)
}
Enter fullscreen mode Exit fullscreen mode

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.

LogRocket Free Trial Banner

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 () => {
  // ...
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

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 />; } }
}
Enter fullscreen mode Exit fullscreen mode

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>
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Or, if you’re using Yarn:

yarn add react@^16.9.0 react-dom@^16.9.0
Enter fullscreen mode Exit fullscreen mode

Happy hacking!


Editor's note: Seeing something wrong with this post? You can find the correct version here.

Plug: LogRocket, a DVR for web apps

 
LogRocket Dashboard Free Trial Banner
 
LogRocket is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.
 
In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.
 
Try it for free.


The post What’s new in React 16.9: Profiler API, bug fixes, and more appeared first on LogRocket Blog.

Top comments (0)