6. Convert To A Reusable Component

6.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 subcomponent called FaqItem. The data is passed to the subcomponent using properties. In the FaqItem component, you will have access to the properties with props.question. The App.js code will be changed to:

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

Differences

--- a/src/App.js
+++ b/src/App.js
@@ -1,31 +1,30 @@
 import "./App.css";
+import FaqItem from "./components/FaqItem";

 function App() {
   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>
+          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.
-        </p>
-      </li>
+          arrive."
+      />
     </ul>
   );
 }

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

components/FaqItem.jsx

 1import "./FaqItem.css";
 2
 3const FaqItem = (props) => {
 4  return (
 5    <li className="faq-item">
 6      <h2 className="question">{props.question}</h2>
 7      <p>{props.answer}</p>
 8    </li>
 9  );
10};
11
12export default FaqItem;

6.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 function 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 "./FaqItem.css";
 2import PropTypes from "prop-types";
 3
 4const FaqItem = (props) => {
 5  return (
 6    <li className="faq-item">
 7      <h2 className="question">{props.question}</h2>
 8      <p>{props.answer}</p>
 9    </li>
10  );
11};
12
13FaqItem.propTypes = {
14  question: PropTypes.string.isRequired,
15  answer: PropTypes.string.isRequired,
16};
17
18export default FaqItem;