10. Use Callbacks To Delete An Item

10.1. Add Delete Button

To be able to manage our FAQ entries, we start by adding a delete button to remove an item from the list. Add the delete button to the FaqItem view in the FaqItem.jsx file. Create an empty onDelete handler which is called when the button is pressed.

Solution

 1import { useState } from "react";
 2import "./FaqItem.css";
 3import PropTypes from "prop-types";
 4
 5const FaqItem = (props) => {
 6  const [isAnswer, setAnswer] = useState(false);
 7
 8  const toggle = () => {
 9    setAnswer(!isAnswer);
10  };
11  const ondelete = () => {};
12
13  return (
14    <li className="faq-item">
15      <h2 className="question" onClick={toggle}>
16        {props.question}
17      </h2>
18      {isAnswer && <p>{props.answer}</p>}
19      <button onClick={ondelete}>Delete</button>
20    </li>
21  );
22};
23
24FaqItem.propTypes = {
25  question: PropTypes.string.isRequired,
26  answer: PropTypes.string.isRequired,
27};
28
29export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -8,6 +8,7 @@ const FaqItem = (props) => {
   const toggle = () => {
     setAnswer(!isAnswer);
   };
+  const ondelete = () => {};

   return (
     <li className="faq-item">
@@ -15,6 +16,7 @@ const FaqItem = (props) => {
         {props.question}
       </h2>
       {isAnswer && <p>{props.answer}</p>}
+      <button onClick={ondelete}>Delete</button>
     </li>
   );
 };

10.2. Write The onDelete Handler

Now that we have our dummy handler ready, we need to add functionality to the handler. Since the list of FAQ items is managed by our App component, we cannot directly remove the item. Rewrite the FaqItem component so that both a unique identifier of the FAQ item and a callback to remove the FAQ item can be passed to this component. Also complete the onDelete handler such that it will call the callback with the correct identifier.

Solution

 1import { useState } from "react";
 2import "./FaqItem.css";
 3import PropTypes from "prop-types";
 4
 5const FaqItem = (props) => {
 6  const [isAnswer, setAnswer] = useState(false);
 7
 8  const toggle = () => {
 9    setAnswer(!isAnswer);
10  };
11  const ondelete = () => {
12    props.onDelete(props.index);
13  };
14
15  return (
16    <li className="faq-item">
17      <h2 className="question" onClick={toggle}>
18        {props.question}
19      </h2>
20      {isAnswer && <p>{props.answer}</p>}
21      <button onClick={ondelete}>Delete</button>
22    </li>
23  );
24};
25
26FaqItem.propTypes = {
27  question: PropTypes.string.isRequired,
28  answer: PropTypes.string.isRequired,
29  index: PropTypes.number.isRequired,
30  onDelete: PropTypes.func.isRequired,
31};
32
33export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -8,7 +8,9 @@ const FaqItem = (props) => {
   const toggle = () => {
     setAnswer(!isAnswer);
   };
-  const ondelete = () => {};
+  const ondelete = () => {
+    props.onDelete(props.index);
+  };

   return (
     <li className="faq-item">
@@ -24,6 +26,8 @@ const FaqItem = (props) => {
 FaqItem.propTypes = {
   question: PropTypes.string.isRequired,
   answer: PropTypes.string.isRequired,
+  index: PropTypes.number.isRequired,
+  onDelete: PropTypes.func.isRequired,
 };

 export default FaqItem;

10.3. Write A Dummy Delete Handler

Now we're ready to change the App component to add a dummy onDelete handler. Add the onDelete handler to the App component, which logs the index of the FAQ item to the console. Make sure to pass the index and the callback to the FaqItem component to wire everything together:

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 onDelete = (index) => {
18    console.log(index);
19  };
20
21  return (
22    <ul>
23      {faqList.map((item, index) => (
24        <FaqItem
25          question={item.question}
26          answer={item.answer}
27          index={index}
28          onDelete={onDelete}
29        />
30      ))}
31    </ul>
32  );
33}
34
35export default App;
--- a/src/App.js
+++ b/src/App.js
@@ -14,10 +14,19 @@ function App() {
     },
   ]);

+  const onDelete = (index) => {
+    console.log(index);
+  };
+
   return (
     <ul>
-      {faqList.map((item) => (
-        <FaqItem question={item.question} answer={item.answer} />
+      {faqList.map((item, index) => (
+        <FaqItem
+          question={item.question}
+          answer={item.answer}
+          index={index}
+          onDelete={onDelete}
+        />
       ))}
     </ul>
   );

10.4. Delete The FAQ Item From The List

The last step is to remove the item from the list. Write the onDelete handler which removes the item from the list and creates the new state.

Solution

17  const onDelete = (index) => {
18    let faq = [...faqList];
19    faq.splice(index, 1);
20    setFaqList(faq);
21  };
--- a/src/App.js
+++ b/src/App.js
@@ -15,7 +15,9 @@ function App() {
   ]);

   const onDelete = (index) => {
-    console.log(index);
+    let faq = [...faqList];
+    faq.splice(index, 1);
+    setFaqList(faq);
   };

   return (