37

Pure functional components in React

 5 years ago
source link: https://www.tuicool.com/articles/hit/ne67j2R
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Speaking about JavaScript frameworks at such a time as this can never be complete if nothing is said about the React framework created and maintained by the team at Facebook.

React is used massively in tons of production apps out there, running on varying platforms ranging from web to mobile devices.

This article focuses on the new experimental React.pure() API, which has the likelihood of being part of the next stable release of the React framework. Hence, you are advised not to use this feature in any production app.

You can keep with the changes that may happen to the React.pure() API on the React RFCs repository .

React components

Like most modern JavaScript frameworks, React is a component-based framework. In React terms, a component is usually defined as a function of its state and props .

If you have used React for some time, you should already know that it supports two flavors of components, namely: class components and functional components .

The following code snippet shows a simple ReactHeader component defined as both a class component and a functional component:

// CLASS COMPONENT
class ReactHeader extends React.Component {
  render() {
    return (
      <h1>
        React {this.props.version || 16} Documentation
      </h1>
    )
  }
}


// FUNCTIONAL COMPONENT
function ReactHeader(props) {
  return (
    <h1>
      React {props.version || 16} Documentation
    </h1>
  )
}

Pure components

Based on the concept of purity in functional programming paradigms, a function is said to be pure if :

  • its return value is only determined by its input values.
  • its return value is always the same for the same input values.

A React component can be considered pure if it renders the same output for the same state and props . For class components like this, React provides the PureComponent base class. Class components that extend the React.PureComponent class are treated as pure components.

Pure components have some performance improvements and render optimizations since React implements the shouldComponentUpdate() method for them with a shallow comparison for props and state.

The following code snippet shows a very simple, pure React component:

import React from 'react';

class PercentageStat extends React.PureComponent {

  render() {
    const { label, score = 0, total = Math.max(1, score) } = this.props;

    return (
      <div>
        <h6>{ label }</h6>
        <span>{ Math.round(score / total * 100) }%</span>
      </div>
    )
  }

}

export default PercentageStat;

Pure functional components

Functional components are very useful in React, especially when you want to isolate state management from the component. Which is why they are often called stateless components .

However, functional components cannot leverage on the performance improvements and render optimizations that come with React.PureComponent since they are not classes by definition.

In fact, if you have a functional component, and you want React to treat it as a pure component, you will have to convert the functional component to a class component that extends React.PureComponent .

Here is a simple example ( still using the PercentageStat component from before ):

// FUNCTIONAL COMPONENT
function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}


// CONVERTED TO PURE COMPONENT
class PercentageStat extends React.PureComponent {

  render() {
    const { label, score = 0, total = Math.max(1, score) } = this.props;

    return (
      <div>
        <h6>{ label }</h6>
        <span>{ Math.round(score / total * 100) }%</span>
      </div>
    )
  }

}

Using pure HOC from Recompose

Optimizing a functional component so that React can treat it as a pure component shouldn’t necessarily require that the component be converted to a class component.

If you are already familiar with the recompose package then you know that it provides a wide collection of higher-order components that makes it very useful when dealing with functional components.

The recompose package exports a {pure} higher-order component that tries to optimize a React component by preventing updates on the component unless a prop has changed, using shallowEqual() to test for changes.

Using the pure higher-order component, our functional component can be wrapped as follows:

import React from 'react';
import { pure } from 'recompose';

function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}

// Wrap component using the `pure` HOC from recompose
export default pure(PercentageStat);

Introducing React.pure()

Although the React framework has gone through several iterations of changes over the years, a couple more improvements and additions are still being made to the framework on a regular basis. You can see the change logs for the framework in the official React repository .

A few days ago, Dan Abramov from the core React team tweeted about some additional features that are undergoing review for the next minor release of React ( v16.6.0 ).

One of these new features is the React.pure() API, which provides a means of optimizing functional components in a much similar fashion to how class components can be optimized using React.PureComponent .

Here is the tweet:

Just published an RFC for React.pure() which lets you optimize function components - similar to PureComponent in classes. Feedback welcome! https://github.com/reactjs/rfcs/pull/63

— @ dan_abramov

The React.pure() API is available from React 16.6.0-alpha.400d197 . To try it out, you will need to install this version of React (or higher) as follows:

Installing with NPM:

npm install --save [email protected] \
[email protected]

Installing with Yarn:

yarn add [email protected] [email protected]

With React.pure() , you can now have memoized functional components that bail out of rendering on unnecessary updates using a shallow comparison of props.

Using the new React.pure() API, the previous functional component can be wrapped as follows:

import React, { pure } from 'react';

function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}

// Wrap component using `React.pure`
export default pure(PercentageStat);

Custom bailout condition

The React.pure() API can take a second argument, which is the arePropsEqual function. This function allows you to customize the condition for bailing out from component updates. If this function returns true , then the component does not re-render.

The arePropsEqual is defined with two parameters: prevProps and nextProps respectively. The following code snippet uses a custom bailout condition:

import React, { pure } from 'react';

function PercentageStat({ label, score = 0, total = Math.max(1, score) }) {
  return (
    <div>
      <h6>{ label }</h6>
      <span>{ Math.round(score / total * 100) }%</span>
    </div>
  )
}

function arePropsEqual(prevProps, nextProps) {
  return prevProps.label === nextProps.label; 
}

// Wrap component using `React.pure` and pass `arePropsEqual`
export default pure(PercentageStat, arePropsEqual);

Implementation details

There are a few things worth knowing about the implementation of the React.pure() API:

  1. React.pure() is not a higher-order component . Although it takes a functional component (type) as its first argument, it does not return a React component.
  2. React.pure() returns a special React component type — that allows the renderer to render the functional component while memoizing the output. Hence, bailing out of updates if the component’s props are shallowly equal.
  3. React.pure() only works with functional components . The first argument passed to React.pure() must be a functional component. Class components just wouldn’t work. For class components, you should use React.PureComponent .

Conclusion

Since the React.pure() is still under review, a lot might change before it is finally released as part of a stable React version. Hence, you are advised not to use this feature in any production app as this may lead to issues.

You can keep up with the changes that may happen to React.pure() on the React RFCs repository.

Enjoy coding…

Plug:LogRocket, a DVR for web apps

rQ367jV.png!webhttps://logrocket.com/signup/

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.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK