[Full Stack React] Day 11: Pure Components

Keywords: Javascript React

This article is reproduced from: Mass translation
Translator: iOSDevLog
Links: http://www.zcfy.cc/article/3819
Original: https://www.fullstackreact.com/30-days-of-react/day-11/

React provides several different ways to create components.Today we will discuss the final solution for creating components, pure components of stateless functions.

We have studied several different ways to build response components.One method we missed from this point is the stateless component/functional approach to building React components.

As we have already seen, we only use the React.Component and React.createClass() methods to build components.For more performance and simplicity, React _Similarly _allows us to create pure, stateless components using normal JavaScript functions.

Pure components can replace components with render-only functionality.Instead of having a complete component just present some content to the screen, we can create a _pure_one instead.

The _pure_component is the simplest and fastest component we can write.They are easy to write, easy to use, and the fastest components we can write.Before we go deeper _why _these are better, let's write one, or a pair!

// The simplest one
const HelloWorld = () => (<div>Hello world</div>);

// A Notification component
const Notification = (props) => {
  const {level, message} = props;
  const classNames = ['alert', 'alert-' + level]
  return (
    <div className={classNames}>
      {message}
    </div>
  )
};

// In ES5
var ListItem = function(props) {
  var handleClick = function(event) {
    props.onClick(event);
  };

  return (
    <div className="list">
      <a
        href="#"
        onClick={handleClick}>
          {props.children}
      </a>
    </div>
  )
}

So they're just functions, right?Yes!Since they are just functions, testing with pure JavaScript is straightforward.The idea is that if React knows props sent to a component and knows whether they must be re-delivered, this may be deterministic.The same attributes are in the same output virtual DOM.

In React, a functional component is called a parameter's props (similar to the React.Component constructor class), which are the props it calls, as well as the current context of the component tree.

For example, suppose we want to use functional components to rewrite our original Timer components because we want to give users a dynamic way to set their own clock style (24/12 hour clocks use different separators, perhaps they don't want to display seconds, etc.).

We can decompose our clock into components, and we can use each time period as a single component.We might break them like this:

const Hour    = (props) => {
  let {hours} = props;
  if (hours === 0) { hours = 12; }
  if (props.twelveHours) { hours -= 12; }
  return (<span>{hours}</span>)
}
const Minute  = ({minutes}) => (<span>{minutes<10 && '0'}{minutes}</span>)
const Second  = ({seconds}) => (<span>{seconds<10 && '0'}{seconds}</span>)
const Separator = ({separator}) => (<span>{separator || ':'}</span>)
const Ampm = ({hours}) => (<span>{hours >= 12 ? 'pm' : 'am'}</span>)

With these, we can place individual components by being full React components (they are):

<div>Minute: <Minute minutes={12} /></div>
<div>Second: <Second seconds={51} /></div>

We can reconstruct our clock component to accept the format string and decompose it to select only the components that are of interest to the user.There are several ways to solve this problem, such as forcing logic into the Clock component _or _we can create another stateless component that accepts format strings.Let's do this (easier to test):

const Formatter = (props) => {
  let children = props.format.split('').map((e, idx) => {
    if (e === 'h') {
      return <Hour key={idx} {...props} />
    } else if (e === 'm') {
      return <Minute key={idx} {...props} />
    } else if (e === 's') {
      return <Second key={idx} {...props} />
    } else if (e === 'p') {
      return <Ampm key={idx} {...props} />
    } else if (e === ' ') {
      return <span key={idx}> </span>;
    } else {
      return <Separator key={idx} {...props} />
    }
  });

  return <span>{children}</span>;
}

This is a bit of an ugly key and {...props} stuff.React gives us some help mapping children's attributes and handles each child's unique key through the React.Children object.

The render() function of the Clock component can be greatly simplified, thanks to the Formatter`component:

class Clock extends React.Component {
  state = { currentTime: new Date() }
  componentDidMount() {
    this.setState({
      currentTime: new Date()
    }, this.updateTime);
  }
  componentWillUnmount() {
    if (this.timerId) {
      clearTimeout(this.timerId)
    }
  }

  updateTime = e => {
    this.timerId = setTimeout(() => {
      this.setState({
        currentTime: new Date()
      }, this.updateTime);
    })
  }

  render() {
    const { currentTime } = this.state
    const hour = currentTime.getHours();
    const minute = currentTime.getMinutes();
    const second = currentTime.getSeconds();

    return (
      <div className='clock'>
        <Formatter
          {...this.props}
          state={this.state}
          hours={hour}
          minutes={minute}
          seconds={second}
        />
      </div>
    )
  }
}

Our Clock components are not only simpler but also easier to test.It_also_will help us transition to using data state trees, such as the Flux / Redux framework, but more in the future.

Uh... so why care?

The advantages of using functional components in React are:

  • We can get rid of bulky components, no constructors, states, extremely foolish life cycles, etc.
  • No this keyword (i.e. no binding required)
  • Demonstration components (also known as dummy components) emphasize that the UI goes beyond business logic (that is, there is no state manipulation in the component)
  • Encourage smaller, independent components
  • Emphasize strict code (better refactoring)
  • Fast, fast, fast (3 important words)
  • They are _easy_reusable

You might say why not use functional components?There are some advantages to using functional components:

  • No lifecycle callback hook function
  • Limited functionality
  • No this keyword

Overall, it's a good idea to like trying out functional components in their heavier React.Component cousins.When we talk about data management in React, we'll see how we use these presentation components and data as pure props.

Good work today, we've successfully achieved the React level.We now know _three_ways to make React components.Tomorrow, we will use the package management tools developed by the React team to set up the React application using/building: create-react-app.

Posted by alexhard on Fri, 07 Jun 2019 10:38:08 -0700