Skip to content
Advertisement

How do I delete a list item that has been given a unique id when created, in React + Firebase?

I am creating a Todo list using React and Firebase. So far, I have already created the AddToDo functionality, however, now I am having trouble with the delete functionality. I believe this is where my problem lies. For example, when I try and click the delete icon that I set up, I get an error:

Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'id')

This is the code if it helps. AddLink.js

import { useState, useEffect } from "react";
import classes from "./addlink.module.css";

import firebase from "firebase/app";
import initFirebase from "../../config";
import "firebase/firestore";

import Todo from "../Todo/Todo";

import { v4 as uuidv4 } from "uuid";

initFirebase();
const db = firebase.firestore();

function AddLink(props) {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState("");

  useEffect(() => {
    db.collection("links")
      .orderBy("timestamp", "desc")
      .onSnapshot((snapshot) => {
        // this gives back an array
        setTodos(
          snapshot.docs.map((doc) => ({
            id: doc.id,
            todo: doc.data().todo,
          }))
        );
      });
  }, []);

  const addTodo = (event) => {
    event.preventDefault();

    console.log("clicked");

    db.collection("links").add({
      id: uuidv4(),
      todo: input,
      timestamp: firebase.firestore.FieldValue.serverTimestamp(),
    });
    setInput("");
  };

  return (
    <div className={classes.addlink}>
      <form>
        <div className={classes.adminlink}>
          <input
            type="text"
            value={input}
            onChange={(event) => setInput(event.target.value)}
          />
          <button
            className={classes.adminbutton}
            type="submit"
            onClick={addTodo}
          >
            Add new link
          </button>
        </div>
      </form>
      {todos.map((todo, id) => (
        <Todo value={todo} key={id} />
      ))}
      {/* {modalIsOpen && (
          <Modal onCancel={closeModalHandler} onConfirm={closeModalHandler} />
        )}
        {modalIsOpen && <Backdrop onCancel={closeModalHandler} />} */}
    </div>
  );
}

export default AddLink;

And Todo.js

import React from "react";
import { AiOutlinePicture } from "react-icons/ai";
import { AiOutlineStar } from "react-icons/ai";
import { GoGraph } from "react-icons/go";
import DeleteForeverIcon from "@material-ui/icons/DeleteForever";

import classes from "./todo.module.css";

import firebase from "firebase/app";
import initFirebase from "../../config";
import "firebase/firestore";

initFirebase();
const db = firebase.firestore();

function Todo(props) {
  const deleteHandler = () => {
    db.collection("todos").doc(props.todo.id).delete();
  };

  return (
    <li className={classes.adminsection}>
      <div className={classes.linkCards}>
        <h3>{props.text}</h3>
        <p>This is a new link</p>
        <div>
          <AiOutlinePicture />
          <AiOutlineStar />
          <GoGraph />
          <DeleteForeverIcon onClick={deleteHandler} />
        </div>
      </div>
    </li>
  );
}

export default Todo;

Any help would be greatly appreciated.

Advertisement

Answer

 const deleteHandler = () => {
    db.collection("todos").doc(props.todo.id).delete();
  };

You should replace props.todo.id with props.value.id.

 const deleteHandler = () => {
    db.collection("todos").doc(props.value.id).delete();
  };

Alternatively you can change:

<Todo value={todo} key={id} />

To

<Todo todo={todo} key={id} />

The key you use to access props.value should be the same as the one declared in the jsx template. Using proptypes can help you avoid those mistakes.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement