9. Use Callbacks To Delete An Item

9.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 and create an empty onDelete handler which is called when the button is pressed.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import React, { Component } from "react";
import PropTypes from "prop-types";
import "./FaqItem.css";

class FaqItem extends Component {
  static propTypes = {
    question: PropTypes.string.isRequired,
    answer: PropTypes.string.isRequired
  };

  constructor(props) {
    super(props);
    this.toggle = this.toggle.bind(this);
    this.onDelete = this.onDelete.bind(this);
    this.state = {
      show: false
    };
  }

  toggle() {
    this.setState({
      show: !this.state.show
    });
  }

  onDelete() {}

  render() {
    return (
      <li className="faq-item">
        <h2 onClick={this.toggle} className="question">
          {this.props.question}
        </h2>
        {this.state.show && <p>{this.props.answer}</p>}
        <button onClick={this.onDelete}>Delete</button>
      </li>
    );
  }
}

export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -11,6 +11,7 @@ class FaqItem extends Component {
  constructor(props) {
    super(props);
    this.toggle = this.toggle.bind(this);
+    this.onDelete = this.onDelete.bind(this);
    this.state = {
      show: false
    };
@@ -22,6 +23,8 @@ class FaqItem extends Component {
    });
  }

+  onDelete() {}
+
  render() {
    return (
      <li className="faq-item">
@@ -29,6 +32,7 @@ class FaqItem extends Component {
          {this.props.question}
        </h2>
        {this.state.show && <p>{this.props.answer}</p>}
+        <button onClick={this.onDelete}>Delete</button>
      </li>
    );
  }

9.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 can not directly remove the item. Rewrite the FaqItem component so that 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 so it will call the callback with the correct identifier.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import React, { Component } from "react";
import PropTypes from "prop-types";
import "./FaqItem.css";

class FaqItem extends Component {
  static propTypes = {
    question: PropTypes.string.isRequired,
    answer: PropTypes.string.isRequired,
    index: PropTypes.number.isRequired,
    onDelete: PropTypes.func.isRequired
  };

  constructor(props) {
    super(props);
    this.toggle = this.toggle.bind(this);
    this.onDelete = this.onDelete.bind(this);
    this.state = {
      show: false
    };
  }

  toggle() {
    this.setState({
      show: !this.state.show
    });
  }

  onDelete() {
    this.props.onDelete(this.props.index);
  }

  render() {
    return (
      <li className="faq-item">
        <h2 onClick={this.toggle} className="question">
          {this.props.question}
        </h2>
        {this.state.show && <p>{this.props.answer}</p>}
        <button onClick={this.onDelete}>Delete</button>
      </li>
    );
  }
}

export default FaqItem;
--- a/src/components/FaqItem.jsx
+++ b/src/components/FaqItem.jsx
@@ -5,7 +5,9 @@ import "./FaqItem.css";
class FaqItem extends Component {
  static propTypes = {
    question: PropTypes.string.isRequired,
-    answer: PropTypes.string.isRequired
+    answer: PropTypes.string.isRequired,
+    index: PropTypes.number.isRequired,
+    onDelete: PropTypes.func.isRequired
  };

  constructor(props) {
@@ -23,7 +25,9 @@ class FaqItem extends Component {
    });
  }

-  onDelete() {}
+  onDelete() {
+    this.props.onDelete(this.props.index);
+  }

  render() {
    return (

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import React, { Component } from "react";
import FaqItem from "./components/FaqItem";
import "./App.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.onDelete = this.onDelete.bind(this);
    this.state = {
      faq: [
        {
          question: "What does the Plone Foundation do?",
          answer:
            "The mission of the Plone Foundation is to protect and..."
        },
        {
          question: "Why does Plone need a Foundation?",
          answer:
            "Plone has reached critical mass, with enterprise..."
        }
      ]
    };
  }

  onDelete(index) {
    console.log(index);
  }

  render() {
    return (
      <ul>
        {this.state.faq.map((item, index) => (
          <FaqItem
            question={item.question}
            answer={item.answer}
            index={index}
            onDelete={this.onDelete}
          />
        ))}
      </ul>
    );
  }
}

export default App;
--- a/src/App.js
+++ b/src/App.js
@@ -5,6 +5,7 @@ import "./App.css";
class App extends Component {
  constructor(props) {
    super(props);
+    this.onDelete = this.onDelete.bind(this);
    this.state = {
      faq: [
        {
@@ -19,11 +20,20 @@ class App extends Component {
    };
  }

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

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

23
24
25
26
27
28
29
onDelete(index) {
  let faq = this.state.faq;
  faq.splice(index, 1);
  this.setState({
    faq
  });
}
--- a/src/App.js
+++ b/src/App.js
@@ -21,7 +21,11 @@ class App extends Component {
  }

  onDelete(index) {
-    console.log(index);
+    let faq = this.state.faq;
+    faq.splice(index, 1);
+    this.setState({
+      faq
+    });
  }

  render() {