12. Use Initial Form Data To Edit An Item#

12.1. Two Modes For The FAQ Item#

We will use inline editing to edit an item. Create a button to switch to "edit" mode. This mode should be set in the state. Change the render method to show a form (similar to the "add" form) in "edit" mode, and the view we currently have in the "view" mode. The onSave handler can be a dummy handler for now. First we will focus on the two modes.

Solution
 1import { useState } from "react";
 2import "./FaqItem.css";
 3import PropTypes from "prop-types";
 4
 5const FaqItem = (props) => {
 6  const [isAnswer, setAnswer] = useState(false);
 7  const [isEditMode, setIsEditMode] = useState(false);
 8
 9  const toggle = () => {
10    setAnswer(!isAnswer);
11  };
12  const ondelete = () => {
13    props.onDelete(props.index);
14  };
15
16  const onEdit = () => {
17    setIsEditMode(true);
18  };
19
20  const onSave = (e) => {
21    e.preventDefault();
22    setIsEditMode(false);
23  };
24
25  return (
26    <>
27      {isEditMode ? (
28        <li className="faq-item">
29          <form onSubmit={onSave}>
30            <label>
31              Question:
32              <input name="question" />
33            </label>
34            <label>
35              Answer:
36              <textarea name="answer" />
37            </label>
38            <input type="submit" value="Save" />
39          </form>
40        </li>
41      ) : (
42        <li className="faq-item">
43          <h2 className="question" onClick={toggle}>
44            {props.question}
45          </h2>
46          {isAnswer && <p>{props.answer}</p>}
47          <button onClick={ondelete}>Delete</button>
48          <button onClick={onEdit}>Edit</button>
49        </li>
50      )}
51    </>
52  );
53};
54
55FaqItem.propTypes = {
56  question: PropTypes.string.isRequired,
57  answer: PropTypes.string.isRequired,
58  index: PropTypes.number.isRequired,
59  onDelete: PropTypes.func.isRequired,
60};
61
62export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";

 const FaqItem = (props) => {
   const [isAnswer, setAnswer] = useState(false);
+  const [isEditMode, setIsEditMode] = useState(false);

   const toggle = () => {
     setAnswer(!isAnswer);
@@ -12,14 +13,42 @@ const FaqItem = (props) => {
     props.onDelete(props.index);
   };

+  const onEdit = () => {
+    setIsEditMode(true);
+  };
+
+  const onSave = (e) => {
+    e.preventDefault();
+    setIsEditMode(false);
+  };
+
   return (
-    <li className="faq-item">
-      <h2 className="question" onClick={toggle}>
-        {props.question}
-      </h2>
-      {isAnswer && <p>{props.answer}</p>}
-      <button onClick={ondelete}>Delete</button>
-    </li>
+    <>
+      {isEditMode ? (
+        <li className="faq-item">
+          <form onSubmit={onSave}>
+            <label>
+              Question:
+              <input name="question" />
+            </label>
+            <label>
+              Answer:
+              <textarea name="answer" />
+            </label>
+            <input type="submit" value="Save" />
+          </form>
+        </li>
+      ) : (
+        <li className="faq-item">
+          <h2 className="question" onClick={toggle}>
+            {props.question}
+          </h2>
+          {isAnswer && <p>{props.answer}</p>}
+          <button onClick={ondelete}>Delete</button>
+          <button onClick={onEdit}>Edit</button>
+        </li>
+      )}
+    </>
   );
 };

12.2. Wiring Everything Together#

Create a controlled form like the add form, and pass an onEdit handler to the FaqItem component, like we did with the onDelete.

FaqItem.jsx
 1import { useState } from "react";
 2import "./FaqItem.css";
 3import PropTypes from "prop-types";
 4
 5const FaqItem = (props) => {
 6  const [isAnswer, setAnswer] = useState(false);
 7  const [isEditMode, setIsEditMode] = useState(false);
 8  const [question, setQuestion] = useState("");
 9  const [answer, setQuestionAnswer] = useState("");
10
11  const toggle = () => {
12    setAnswer(!isAnswer);
13  };
14  const ondelete = () => {
15    props.onDelete(props.index);
16  };
17
18  const onEdit = () => {
19    setIsEditMode(true);
20    setQuestionAnswer(props.answer);
21    setQuestion(props.question);
22  };
23
24  const onChangeAnswer = (e) => {
25    setQuestionAnswer(e.target.value);
26  };
27  const onChangeQuestion = (e) => {
28    setQuestion(e.target.value);
29  };
30
31  const onSave = (e) => {
32    e.preventDefault();
33    setIsEditMode(false);
34    props.onEdit(props.index, question, answer);
35  };
36
37  return (
38    <>
39      {isEditMode ? (
40        <li className="faq-item">
41          <form onSubmit={onSave}>
42            <label>
43              Question:
44              <input
45                name="question"
46                value={question}
47                onChange={onChangeQuestion}
48              />
49            </label>
50            <label>
51              Answer:
52              <textarea
53                name="answer"
54                value={answer}
55                onChange={onChangeAnswer}
56              />
57            </label>
58            <input type="submit" value="Save" />
59          </form>
60        </li>
61      ) : (
62        <li className="faq-item">
63          <h2 className="question" onClick={toggle}>
64            {props.question}
65          </h2>
66          {isAnswer && <p>{props.answer}</p>}
67          <button onClick={ondelete}>Delete</button>
68          <button onClick={onEdit}>Edit</button>
69        </li>
70      )}
71    </>
72  );
73};
74
75FaqItem.propTypes = {
76  question: PropTypes.string.isRequired,
77  answer: PropTypes.string.isRequired,
78  index: PropTypes.number.isRequired,
79  onDelete: PropTypes.func.isRequired,
80  onEdit: PropTypes.func.isRequired,
81};
82
83export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -5,6 +5,8 @@ import PropTypes from "prop-types";
 const FaqItem = (props) => {
   const [isAnswer, setAnswer] = useState(false);
   const [isEditMode, setIsEditMode] = useState(false);
+  const [question, setQuestion] = useState("");
+  const [answer, setQuestionAnswer] = useState("");

   const toggle = () => {
     setAnswer(!isAnswer);
@@ -15,11 +17,21 @@ const FaqItem = (props) => {

   const onEdit = () => {
     setIsEditMode(true);
+    setQuestionAnswer(props.answer);
+    setQuestion(props.question);
+  };
+
+  const onChangeAnswer = (e) => {
+    setQuestionAnswer(e.target.value);
+  };
+  const onChangeQuestion = (e) => {
+    setQuestion(e.target.value);
   };

   const onSave = (e) => {
     e.preventDefault();
     setIsEditMode(false);
+    props.onEdit(props.index, question, answer);
   };

   return (
@@ -29,11 +41,19 @@ const FaqItem = (props) => {
           <form onSubmit={onSave}>
             <label>
               Question:
-              <input name="question" />
+              <input
+                name="question"
+                value={question}
+                onChange={onChangeQuestion}
+              />
             </label>
             <label>
               Answer:
-              <textarea name="answer" />
+              <textarea
+                name="answer"
+                value={answer}
+                onChange={onChangeAnswer}
+              />
             </label>
             <input type="submit" value="Save" />
           </form>
@@ -57,6 +77,7 @@ FaqItem.propTypes = {
   answer: PropTypes.string.isRequired,
   index: PropTypes.number.isRequired,
   onDelete: PropTypes.func.isRequired,
+  onEdit: PropTypes.func.isRequired,
 };

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

+  const onEdit = (index, question, answer) => {
+    const faq = [...faqList];
+    faq[index] = { question, answer };
+    setFaqList(faq);
+  };
+
   const onSubmit = (e) => {
     e.preventDefault();
     setFaqList([...faqList, { question, answer }]);
@@ -48,6 +54,7 @@ function App() {
             answer={item.answer}
             index={index}
             onDelete={onDelete}
+            onEdit={onEdit}
           />
         ))}
       </ul>