5. Convert To A Reusable Component

5.1. Create A Reusable component

To reuse the markup of a FAQ item we will split up the code. The app component will contain just the data of the FAQ item and will render a newly created sub component called FaqItem. The data is passed to the sub component using properties. In the FaqItem component you will have access to the properties with this.props.question for example. The App.js code will be changed to:

 1import React, { Component } from "react";
 2import FaqItem from "./components/FaqItem";
 3import "./App.css";
 4
 5class App extends Component {
 6  render() {
 7    return (
 8      <ul>
 9        <FaqItem
10          question="What does the Plone Foundation do?"
11          answer="
12            The mission of the Plone Foundation is to protect and promote Plone.
13            The Foundation provides marketing assistance, awareness, and
14            evangelism assistance to the Plone community. The Foundation also
15            assists with development funding and coordination of funding for
16            large feature implementations. In this way, our role is similar to
17            the role of the Apache Software Foundation and its relationship with
18            the Apache Project."
19        />
20        <FaqItem
21          question="Why does Plone need a Foundation?"
22          answer="
23            Plone has reached critical mass, with enterprise implementations and
24            worldwide usage. The Foundation is able to speak for Plone, and
25            provide strong and consistent advocacy for both the project and the
26            community. The Plone Foundation also helps ensure a level playing
27            field, to preserve what is good about Plone as new participants
28            arrive."
29        />
30      </ul>
31    );
32  }
33}
34
35export default App;

Differences

--- a/src/App.js
+++ b/src/App.js
@@ -1,33 +1,32 @@
import React, { Component } from "react";
+import FaqItem from "./components/FaqItem";
import "./App.css";

class App extends Component {
  render() {
    return (
      <ul>
-        <li className="faq-item">
-          <h2 className="question">What does the Plone Foundation do?</h2>
-          <p>
+        <FaqItem
+          question="What does the Plone Foundation do?"
+          answer="
            The mission of the Plone Foundation is to protect and promote Plone.
            The Foundation provides marketing assistance, awareness, and
            evangelism assistance to the Plone community. The Foundation also
            assists with development funding and coordination of funding for
            large feature implementations. In this way, our role is similar to
            the role of the Apache Software Foundation and its relationship with
-            the Apache Project.
-          </p>
-        </li>
-        <li className="faq-item">
-          <h2 className="question">Why does Plone need a Foundation?</h2>
-          <p>
-             Plone has reached critical mass, with enterprise implementations and
+            the Apache Project."
+        />
+        <FaqItem
+          question="Why does Plone need a Foundation?"
+          answer="
+            Plone has reached critical mass, with enterprise implementations and
            worldwide usage. The Foundation is able to speak for Plone, and
            provide strong and consistent advocacy for both the project and the
            community. The Plone Foundation also helps ensure a level playing
            field, to preserve what is good about Plone as new participants
-            arrive.
-          </p>
-        </li>
+            arrive."
+        />
      </ul>
    );
  }

5.2. Exercise

Create the FaqItem component in a newly created folder called components which renders the same output. Also move all the styling of the view to components/FaqItem.css.

Solution

 1import React, { Component } from "react";
 2import "./FaqItem.css";
 3
 4class FaqItem extends Component {
 5  render() {
 6    return (
 7      <li className="faq-item">
 8        <h2 className="question">{this.props.question}</h2>
 9        <p>{this.props.answer}</p>
10      </li>
11    );
12  }
13}
14
15export default FaqItem;

5.3. Property Validation

React has a builtin mechanism to validate the properties being passed in into a component. When incorrect values are passed you will receive a warning in the console. In the above example you have to add an extra import:

import PropTypes from "prop-types";

And the following static property to the class to validate the properties:

static propTypes = {
  question: PropTypes.string.isRequired,
  answer: PropTypes.string.isRequired
};

If you now add a third empty <FaqItem> to App.js, errors of missing properties on this component call will be reported in the Javascript console of your browser.

 1import React, { Component } from "react";
 2import PropTypes from "prop-types";
 3
 4import "./FaqItem.css";
 5
 6class FaqItem extends Component {
 7  static propTypes = {
 8    question: PropTypes.string.isRequired,
 9    answer: PropTypes.string.isRequired
10  };
11
12  render() {
13    return (
14      <li className="faq-item">
15        <h2 className="question">{this.props.question}</h2>
16        <p>{this.props.answer}</p>
17      </li>
18    );
19  }
20}
21
22export default FaqItem;