Stateless components

The components you've seen so far in this book have been classes that extend the base Component class. It's time to learn about functional components in React. In this section, you'll learn what a pure functional component is by implementing one. Then, we'll cover setting default property values for stateless functional components.

Pure functional components

A functional React component is just what it sounds like—a function. Picture the render() method of any React component that you've seen. This method, in essence, is the component. The job of a functional React component is to return JSX, just like a class-based React component. The difference is that this is all a functional component can do. It has no state and no lifecycle methods.

Why would we want to use functional components? It's a matter of simplicity more than anything else. If your component depends on some properties to render some JSX and does nothing else, then why bother with a class when a function is simpler?

A pure function is a function without side effects. That is to say, called with a given set of arguments, the function always produces the same output. This is relevant for React components because, given a set of properties, it's easier to predict what the rendered content will be.

Let's look at a functional component now:

import React from 'react'; 
 
// Exports an arrow function that returns a 
// "<button>" element. This function is pure 
// because it has no state, and will always 
// produce the same output, given the same 
// input. 
export default ({ disabled, text }) => ( 
  <button disabled={disabled}>{text}</button> 
); 

Concise, isn't it? This function returns a <button> element, using the properties passed in as arguments (instead of accessing them through this.props). This function is pure because the same content is rendered if the same disabled and text property values are passed. Now let's see how to render this component:

import React from 'react'; 
import { render as renderJSX } from 'react-dom'; 
 
// "MyButton" is a function, instead of a 
// "Component" subclass. 
import MyButton from './MyButton'; 
 
// Renders two "MyButton" components. We only need 
// the "first" and "second" properties from the 
// props argument by destructuring it. 
function render({ first, second }) { 
  renderJSX(( 
    <main> 
      <MyButton 
        text={first.text} 
        disabled={first.disabled} 
      /> 
      <MyButton 
        text={second.text} 
        disabled={second.disabled} 
      /> 
    </main> 
    ), 
    document.getElementById('app') 
  ); 
} 
 
// Reders the components, passing in property data. 
render({ 
  first: { 
    text: 'First Button', 
    disabled: false, 
  }, 
  second: { 
    text: 'Second Button', 
    disabled: true, 
  }, 
});

As you can see, there's zero difference between class-based and function-based React components, from a JSX point of view. The JSX looks exactly the same whether the component was declared using class or function syntax.

Note

The convention is to use arrow function syntax to declare functional React components. However, it's perfectly valid to declare them using traditional JavaScript function syntax, if that's better suited to your style.

Here's what the rendered HTML looks like:

Defaults in functional components

Functional components are lightweight; they don't have any state or lifecycle. They do, however, support some metadata options. For example, we can specify the default property values of functional components the same way we would with a class-based component. Here's an example of what this looks like:

import React from 'react'; 
 
// The functional component doesn't care if the property 
// values are the defaults, or if they're passed in from 
// JSX. The result is the same. 
const MyButton = ({ disabled, text }) => ( 
  <button disabled={disabled}>{text}</button> 
); 
 
// The "MyButton" constant was created so that we could 
// attach the "defaultProps" metadata here, before 
// exporting it. 
MyButton.defaultProps = { 
  text: 'My Button', 
  disabled: false, 
}; 
 
export default MyButton; 

The defaultProps property is on a function instead of a class. When React encounters a functional component with this property, it knows to pass in the defaults if they're not provided via JSX.