11. Use Forms To Add An Item

11.1. Add The Form

To be able to add FAQ items to the list, we will start by adding an add form:

23return (
24    <div>
25      <ul>
26        {faqList.map((item, index) => (
27          <FaqItem
28            question={item.question}
29            answer={item.answer}
30            index={index}
31            onDelete={onDelete}
32          />
33        ))}
34      </ul>
35      <form>
36        <label>
37          Question: <input name="question" type="text" />
38        </label>
39        <label>
40          Answer: <textarea name="answer" />
41        </label>
42        <input type="submit" value="Add" />
43      </form>
44    </div>
45  );

Differences

--- a/src/App.js
+++ b/src/App.js
@@ -21,16 +21,27 @@ function App() {
   };

   return (
-    <ul>
-      {faqList.map((item, index) => (
-        <FaqItem
-          question={item.question}
-          answer={item.answer}
-          index={index}
-          onDelete={onDelete}
-        />
-      ))}
-    </ul>
+    <div>
+      <ul>
+        {faqList.map((item, index) => (
+          <FaqItem
+            question={item.question}
+            answer={item.answer}
+            index={index}
+            onDelete={onDelete}
+          />
+        ))}
+      </ul>
+      <form>
+        <label>
+          Question: <input name="question" type="text" />
+        </label>
+        <label>
+          Answer: <textarea name="answer" />
+        </label>
+        <input type="submit" value="Add" />
+      </form>
+    </div>
   );
 }

11.2. Manage Field Values In The State

To manage the values of the fields in the form, we will use the state. Add a question and answer value to the state which contains the values of the inputs. Add onChange handlers to the input and textarea which will change the values in the state when the input changes. This pattern is called "controlled inputs".

Solution

 1import { useState } from "react";
 2import "./App.css";
 3import FaqItem from "./components/FaqItem";
 4
 5function App() {
 6  const [faqList, setFaqList] = useState([
 7    {
 8      question: "What does the Plone Foundation do?",
 9      answer: "The mission of the Plone Foundation is to protect and...",
10    },
11    {
12      question: "Why does Plone need a Foundation?",
13      answer: "Plone has reached critical mass, with enterprise...",
14    },
15  ]);
16
17  const [question, setQuestion] = useState("");
18  const [answer, setAnswer] = useState("");
19
20  const onDelete = (index) => {
21    let faq = [...faqList];
22    faq.splice(index, 1);
23    setFaqList(faq);
24  };
25
26  const onChangeAnswer = (e) => {
27    setAnswer(e.target.value);
28  };
29
30  const onChangeQuestion = (e) => {
31    setQuestion(e.target.value);
32  };
33
34  return (
35    <div>
36      <ul>
37        {faqList.map((item, index) => (
38          <FaqItem
39            question={item.question}
40            answer={item.answer}
41            index={index}
42            onDelete={onDelete}
43          />
44        ))}
45      </ul>
46      <form>
47        <label>
48          Question:{" "}
49          <input
50            name="question"
51            type="text"
52            value={question}
53            onChange={onChangeQuestion}
54          />
55        </label>
56        <label>
57          Answer:{" "}
58          <textarea name="answer" value={answer} onChange={onChangeAnswer} />
59        </label>
60        <input type="submit" value="Add" />
61      </form>
62    </div>
63  );
64}
65
66export default App;
--- a/src/App.js
+++ b/src/App.js
@@ -14,12 +14,23 @@ function App() {
     },
   ]);

+  const [question, setQuestion] = useState("");
+  const [answer, setAnswer] = useState("");
+
   const onDelete = (index) => {
     let faq = [...faqList];
     faq.splice(index, 1);
     setFaqList(faq);
   };

+  const onChangeAnswer = (e) => {
+    setAnswer(e.target.value);
+  };
+
+  const onChangeQuestion = (e) => {
+    setQuestion(e.target.value);
+  };
+
   return (
     <div>
       <ul>
@@ -34,10 +45,17 @@ function App() {
       </ul>
       <form>
         <label>
-          Question: <input name="question" type="text" />
+          Question:{" "}
+          <input
+            name="question"
+            type="text"
+            value={question}
+            onChange={onChangeQuestion}
+          />
         </label>
         <label>
-          Answer: <textarea name="answer" />
+          Answer:{" "}
+          <textarea name="answer" value={answer} onChange={onChangeAnswer} />
         </label>
         <input type="submit" value="Add" />
       </form>

11.3. Submit Handler

Now that our values are managed in the state, we can write our submit handler. Write an onSubmit handler which reads the values from the state and adds the new FAQ item to the list. After the item is added, the inputs should also reset to empty values.

Solution

And add this to the body of the function.

34  const onSubmit = (e) => {
35    e.preventDefault();
36    setFaqList([...faqList, { question, answer }]);
37    setQuestion("");
38    setAnswer("");
39  };
40
41  return (
42    <div>
43      <ul>
44        {faqList.map((item, index) => (
45          <FaqItem
46            question={item.question}
47            answer={item.answer}
48            index={index}
49            onDelete={onDelete}
50          />
51        ))}
52      </ul>
53      <form onSubmit={onSubmit}>
54        <label>
55          Question:{" "}
56          <input
57            name="question"
58            type="text"
59            value={question}
60            onChange={onChangeQuestion}
61          />
62        </label>
63        <label>
64          Answer:{" "}
65          <textarea name="answer" value={answer} onChange={onChangeAnswer} />
66        </label>
67        <input type="submit" value="Add" />
68      </form>
69    </div>
70  );
71}
--- a/src/App.js
+++ b/src/App.js
@@ -31,6 +31,13 @@ function App() {
     setQuestion(e.target.value);
   };

+  const onSubmit = (e) => {
+    e.preventDefault();
+    setFaqList([...faqList, { question, answer }]);
+    setQuestion("");
+    setAnswer("");
+  };
+
   return (
     <div>
       <ul>
@@ -43,7 +50,7 @@ function App() {
           />
         ))}
       </ul>
-      <form>
+      <form onSubmit={onSubmit}>
         <label>
           Question:{" "}
           <input