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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, { Component } from "react";
import FaqItem from "./components/FaqItem";
import "./App.css";

class App extends Component {
  render() {
    return (
      <ul>
        <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."
        />
        <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."
        />
      </ul>
    );
  }
}

export 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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import React, { Component } from "react";
import "./FaqItem.css";

class FaqItem extends Component {
  render() {
    return (
      <li className="faq-item">
        <h2 className="question">{this.props.question}</h2>
        <p>{this.props.answer}</p>
      </li>
    );
  }
}

export 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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { Component } from "react";
import PropTypes from "prop-types";

import "./FaqItem.css";

class FaqItem extends Component {
  static propTypes = {
    question: PropTypes.string.isRequired,
    answer: PropTypes.string.isRequired
  };

  render() {
    return (
      <li className="faq-item">
        <h2 className="question">{this.props.question}</h2>
        <p>{this.props.answer}</p>
      </li>
    );
  }
}

export default FaqItem;