Use Initial Form Data To Edit An Item

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            question={item.question}
53            answer={item.answer}
54            index={index}
55            onDelete={onDelete}
56            onEdit={onEdit}
57          />
58        ))}
59      </ul>
60      <form onSubmit={onSubmit}>
61        <label>
62          Question:{" "}
63          <input
64            name="question"
65            type="text"
66            value={question}
67            onChange={onChangeQuestion}
68          />
69        </label>
70        <label>
71          Answer:{" "}
72          <textarea name="answer" value={answer} onChange={onChangeAnswer} />
73        </label>
74        <input type="submit" value="Add" />
75      </form>
76    </div>
77  );
78}
79
80export 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 }]);
@@ -47,6 +53,7 @@ function App() {
             answer={item.answer}
             index={index}
             onDelete={onDelete}
+            onEdit={onEdit}
           />
         ))}
       </ul>