React By Example: Part 6
Introducing stateless functional components and more important properties.
This article is part of a series (starting with React By Example: Part 1) of articles that, through a number of progressively more complicated examples, explores the React JavaScript library. The examples are available as a GitHub repository.
In this part we introduce two new React concepts: stateless functional components and properties.
Stateless Functional Components
In the re-implementation of the counter application in React, the App component has state (initialized in a constructor) as well as a complex render method.
note: Actually the render method in our example is fairly simple; but one can imagine with a typical user-interface there would be a lot of JSX in the render method.
In this case, one common practice is to separate out the complex render method into a separate component; and because it only has a render method, we can use a simplified syntax (stateless functional component) to create it.
Working from our re-implemented counter example, we add the following file:
src/Counter.js
import React from 'react';const Counter = () => (
<div>
<div>0</div>
<button>+</button>
</div>
);
export default Counter;
Observations
- This is a first, non-functional, step.
- It is common practice (but not required) to use the same name, Counter, in the filename and for the exported constant.
- The exported function provides the render method of the resultant component.
To use the component we update App.js as follows:
src/App.js
import React, { Component } from 'react';
import Counter from './Counter';
...
render() {
const { counter } = this.state;
return (
<Counter />
);
...
Observations
- Again, we can now see the number and the button, but it is non-functional.
- The resulting component, after splitting out the meat of the render method into a stateless functional component, is often called a container component.
Properties
In order to make our application functional again we need to update the Counter component to show the counter state and handle the button click. The problem, however, is that the counter state is stored in the parent component App. The solution is for the App component to pass properties to the Counter component.
We have seen properties already, e.g., className, src, and onClick; in these cases they were reserved ones that had special meaning, e.g., assigning a CSS class, defining an HTML attribute, and adding a click handler. We are going to define our own properties.
src/App.js
...
render() {
const { counter } = this.state;
return (
<Counter
increment={() => this.setState({ counter: counter + 1 })}
value={counter === 0 ? 'zero' : counter.toString()}
/>
);
...
Observations
- The application is still non-functional.
- The property names, value and increment, are completely arbitrary; but it is good practice to use something relevant to the problem.
The next step is for us to recognize and use these properties in the Counter component.
import React from 'react';
import { PropTypes } from 'prop-types';const Counter = ({ increment, value }) => (
<div>
<div>{value}</div>
<button
onClick={increment}
>+</button>
</div>
);
Counter.propTypes = {
increment: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
};
export default Counter;
Observations
- With these additions, out application is functional again.
- While the use of propTypes to validate properties is optional, it is recommended.
- The Counter function is passed a single object (referred to as the props) that can be destructured into the component properties.
- When I first wrote this article, PropTypes was supplied by the react package; it is now provided in its own package; prop-types.
The Next Part
In the next part, React by Example: Part 7, we wrap up the series with a cursory look at the component lifecycle and learn about React Developer Tools.