Why React 16 is a Blessing for React Developers

React, the popular JavaScript library for building user interfaces, keeps getting better with every release. React 16 introduced several new features and improvements that simplify development and optimize performance. As an experienced React developer, I‘m excited to share my thoughts on why React 16 is such a blessing for the React community.

In this article, we‘ll dive into the key features of React 16 and explore how they benefit developers. Whether you‘re a seasoned React pro or just getting started, understanding these features will help you write cleaner, more efficient, and more resilient code. Let‘s jump in!

Error Handling with Error Boundaries

One of the standout features of React 16 is improved error handling with error boundaries. In the past, JavaScript errors inside components would corrupt React‘s internal state and cause cryptic errors on subsequent renders. With React 16, you can use error boundaries to gracefully handle these errors.

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI. They catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them.

Here‘s an example of defining an error boundary component:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {    
    return { hasError: true };  
  }

  componentDidCatch(error, errorInfo) {    
    logErrorToMyService(error, errorInfo);  
  }

  render() {
    if (this.state.hasError) {      
      return ;    
    }
    return this.props.children; 
  }
}

With error boundaries, you can provide a better user experience when something goes wrong, and prevent the entire app from breaking. Just wrap error-prone components in an ErrorBoundary component:

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

Error boundaries are a huge step forward for React stability and resilience. By catching and handling errors gracefully, we can create React apps that are more robust and production-ready.

Returning Arrays and Strings from Render

Another nice improvement in React 16 is the ability to return an array of elements from a component‘s render method. In React 15, you had to wrap sibling elements in a parent <div> or use a workaround like returning an array of keyed React elements.

With React 16, you can "skip the wrap" and return a plain array of elements:

render() {
  // No need to wrap list items in an extra element!
  return [
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

React 16 also supports returning strings and numbers from render:

render() {
  return ‘Look ma, no spans!‘;
}

This simplifies the code required for many common UI patterns and keeps the focus on what really matters in your components. It‘s a small but welcome improvement that makes React development a little bit easier.

Portals for Rendering Outside the Hierarchy

Portals are a new feature in React 16 that let you render children into a DOM node that exists outside the hierarchy of the parent component. With portals, you can create components like modal dialogs, tooltips, and hovercards that "break out" of their parent containers.

To create a portal, you use ReactDOM.createPortal(child, container):

render() {
  return ReactDOM.createPortal(
    this.props.children,
    domNode  
  );
}

The first argument is any renderable React child, and the second argument is the target DOM node.

Portals give you more control over the DOM structure and allow you to circumvent CSS overflow and z-index issues. They provide a cleaner way to structure these "escaping" UI elements without relying on complex CSS or JavaScript hacks.

Support for Custom DOM Attributes

In React 15, any unknown DOM attributes were ignored and not rendered to the DOM. With React 16, those custom attributes are now supported and passed through to the DOM.

// React 15 output: <div />
// React 16 output: <div mycustomattribute="something" />
<div mycustomattribute="something" />

This change makes it easier to use React with Web Components or other libraries that rely on custom attributes. You no longer have to use workarounds like data-* attributes or manually set properties on DOM refs.

Avoiding Re-renders with Null Returns

React 16 introduced a small but mighty change to setState() behavior. You can now return null from a setState updater function to signal that the new state is identical to the previous state, and thus avoid triggering a re-render.

this.setState(prevState => {
  // No change, avoid re-render
  if (prevState.count >= MAX_COUNT) {
    return null;
  }
  // Otherwise, update count
  return { count: prevState.count + 1 };
});

In complex applications with deep component trees, avoiding unnecessary re-renders can provide significant performance gains. The ability to short-circuit the update process with a null return is a handy addition to React‘s performance toolbelt.

Simpler Refs with React.createRef

React 16 introduced a new way to create refs with the React.createRef() API. Refs provide a way to access DOM nodes or React elements created in the render method. They can be useful for managing focus, triggering animations, or integrating with third-party libraries.

With createRef(), creating and accessing refs is simpler and more declarative:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);

    this.inputRef = React.createRef();
  }

  componentDidMount() {
    this.inputRef.current.focus();
  }

  render() {
    return <input type="text" ref={this.inputRef} />;
  }
}

React.createRef() creates a ref that can be attached to React elements via the ref attribute. The ref object‘s current property will be set to the corresponding DOM node or React element instance.

This new refs API is more performant and works better with dynamic refs than the older string ref and callback ref approaches. It‘s now the recommended way to create refs in React.

New Context API for Cleaner Data Passing

React 16 also introduced a new context API that makes it easier to pass data through the component tree without having to pass props down manually at every level.

The new context API consists of three main parts:

  • React.createContext for creating a context
  • Provider for providing a context value to descendants
  • Consumer for consuming a context value from the nearest Provider above

Here‘s a simplified example:

const ThemeContext = React.createContext(‘light‘);

class ThemeProvider extends React.Component {
  state = {theme: ‘light‘};

  render() {
    return (
      <ThemeContext.Provider value={this.state.theme}>
        {this.props.children}
      </ThemeContext.Provider>
    );
  }
}

class ThemedButton extends React.Component {
  render() {
    return (
      <ThemeContext.Consumer>
        {theme => <Button theme={theme} />}
      </ThemeContext.Consumer>
    );
  }
}

The new context API is more efficient and supports both static and dynamic values. It provides a cleaner and more composable way to share state across multiple components without resorting to complex patterns like higher-order components or render props.

Static Lifecycle Methods

Finally, React 16 introduced a few changes to component lifecycle methods. The most notable is the addition of the static getDerivedStateFromProps method.

getDerivedStateFromProps is invoked right before calling the render method, both on initial mount and subsequent updates. It takes in the next props and state, and returns an object to update the state or null to indicate no update.

static getDerivedStateFromProps(props, state) {
  if (props.currentRow !== state.lastRow) {
    return {
      isScrollingDown: props.currentRow > state.lastRow,
      lastRow: props.currentRow,
    };
  }
  // Return null to indicate no change to state.
  return null;
}

getDerivedStateFromProps enables a few optimizations and simplifies some complex patterns that were previously accomplished with the componentWillReceiveProps lifecycle. However, it‘s important to note that getDerivedStateFromProps (and derived state in general) should be used sparingly, as it can make components harder to understand.

In most cases, derived state can be avoided by using fully controlled or fully uncontrolled components, or by moving the state updating logic to componentDidUpdate. Still, getDerivedStateFromProps can be useful for certain niche use cases and provides a more declarative way to update state based on prop changes.

Conclusion

As you can see, React 16 introduced several powerful features and ergonomic improvements for React developers. From error boundaries and portal rendering to simplified refs and lifecycle methods, React 16 makes it easier than ever to create robust, performant applications.

By leveraging these new capabilities, we can write cleaner, more efficient React code and provide better user experiences. React 16 truly is a blessing for the React developer community.

Of course, we‘ve only scratched the surface of what‘s new in React 16. To learn more, I recommend diving into the official React documentation and release notes. You can also find numerous blog posts, tutorials, and conference talks exploring React 16 features in greater depth.

I hope this article has piqued your interest and shown you why React 16 is such an exciting release. So go forth and start using these new features in your own React projects! Happy coding!

Similar Posts