This post is part of the series 30 Days of React.

In this series, we're starting from the very basics and walk through everything you need to know to get started with React. If you've ever wanted to learn React, this is the place to start!

Pure Components

Edit this page on Github

React offers several different methods for creating components. Today we'll talk about the final method of creating components, the function stateless pure component.

We've looked at a few different ways to build react components. One method we left out up through this point is the stateless component/functional method of building React components.

As we've seen up through this point, we've only worked through building components using the React.Component and React.createClass() methods. For more performance and simplicity, React also allows us to create pure, stateless components using a normal JavaScript function.

A Pure component can replace a component that only has a render function. Instead of making a full-blown component just to render some content to the screen, we can create a pure one instead.

Pure components are the simplest, fastest components we can write. They are easy to write, simple to reason about, and the quickest component we can write. Before we dive into why these are better, let's write one, or heck a couple!

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

// A Notification component
const Notification = (props) => {
  const {level, message} = props;
  return (
    <div className=`alert alert-${level}`>
      {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 are just functions, right? Yep! Since they are just functions, it's really easy to test using pure JavaScript. The idea is that if React knows the props that are sent into a component, it can be deterministic in knowing if it has to rerender or not. The same props in equal the same output virtual DOM.

In React, functional components are called with an argument of props (similar to the React.Component constructor class), which are the props it's called with as well as with the current context of the component tree.

For instance, let's say we want to rewrite our original Timer component using functional components as we want to give our users a dynamic way to set their own clock styles (24 hour clock vs. 12, different separators, maybe they don't want to display the seconds, etc).

We can break up our clock into multiple components where we can use each block of time as an individual component. We might break them up like so:

const Hour    = (props) => {
  let {hours} = props;
  if (hours == 0) { hours = 12; }
  if (props.twelveHours) { hours = 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 as through they are full-blown React components (they are):

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

We can refactor our clock component to accept a format string and break up this string selecting only the components our user is interested in showing. There are multiple ways we can handle this, like forcing the logic into the Clock component or we can create another stateless component that accepts a format string. Let's do that (easier to test):

export 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 little ugly with the key and {...props} thingie in there. React gives us some helpers for mapping over children and taking care of handling the unique key for each child through the React.Children object.

The render() function of our Clock component can be greatly simplified thanks to the Formatter component into this:

class Clock extends React.Component {
  render() {
    return (
      <div className={styles.clock}>
        <Formatter {...this.props} state={this.state} />
      </div>
    )
  }
}

Not only is our Clock component much simpler, but it's so much easier to test. It also will help us transition to using a data state tree, like Flux/Redux frameworks, but more on those later.

Uhh... so why care?

Advantages to using functional components in React are:

  • We can do away with the heavy lifting of components, no constructor, state, life-cycle madness, etc.
  • There is no this keyword (i.e. no need to bind)
  • Presentational components (also called dumb components) emphasize UI over business logic (i.e. no state manipulation in the component)
  • Encourages building smaller, self-contained components
  • Highlights badly written code (for better refactoring)
  • FAST FAST FAST FAST FAST
  • They are easy to reuse

You might say why not use a functional component? Well, some of the disadvantage of using a functional component are some of the advantages:

  • No life-cycle callback hooks
  • Limited functionality
  • There is no this keyword

Overall, it's a really good idea to try to prefer using functional components over their heavier React.Component cousins. When we get to talking about data management in React, we'll see how we can use these presentational components with data as pure props.

Nice work today. We've successfully achieved React rank after today. We now know the three ways to make a React Component. Tomorrow, we'll get set up using/building React apps with the package management tool shipped by the React team: create-react-app.


Ari Lerner

Hi, I'm Ari. I'm the author of ng-book and I've been teaching Web Development for a long time. I like to speak at conferences and eat spicy food. I technically got paid while I traveled the country as a professional comedian, but have come to terms with the fact that I am not funny.

Connect with Ari on Twitter at @auser.