如何通过单击 React 中的按钮来呈现列表?

How can I render a list by clicking a button in React?

我正在使用 React 和 Firebase 处理待办事项列表。我希望能够单击一个将添加新待办事项的按钮,但将待办事项呈现为列表项。到目前为止,我正在通过列表映射每个待办事项,但是当我添加道具时,当我将鼠标悬停在 VSC 中的错误上时,我收到错误消息 Missing "key" prop for element in iterator。使用按钮单击呈现列表时,如何添加关键道具?如果有帮助,我将代码包含在内。

AddLink.js

import { useState, useEffect } from "react";
import classes from "./addlink.module.css";
import { AiOutlinePicture } from "react-icons/ai";
import { AiOutlineStar } from "react-icons/ai";
import { GoGraph } from "react-icons/go";
import { RiDeleteBin6Line } from "react-icons/ri";

import Modal from "../Modal/Modal";
import Backdrop from "../Backdrop/Backdrop";

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

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

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

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

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

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

    console.log("clicked");

    db.collection("links").add({
      todo: input,
      timestamp: firebase.firestore.FieldValue.serverTimestamp(),
    });
    // empty input after the todo is successfully stored in firebase
    setInput("");
  };

  const deleteLink = () => {
    setModalIsOpen(true);
  };

  const closeModalHandler = () => {
    setModalIsOpen(false);
  };

  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>
        <div className={classes.adminsection}>
          <div className="link-cards">
            <h3>{props.text}</h3>
            <p>This is a new link</p>
            <div>
              <AiOutlinePicture />
              <AiOutlineStar />
              <GoGraph />
              <button onClick={deleteLink}>
                <RiDeleteBin6Line />
              </button>
            </div>
          </div>
        </div>
        {todos.map((todo) => (
          <Todo todo={todo} /> //This is where I am getting the error message
        ))}
        {modalIsOpen && (
          <Modal onCancel={closeModalHandler} onConfirm={closeModalHandler} />
        )}
        {modalIsOpen && <Backdrop onCancel={closeModalHandler} />}
      </form>
    </div>
  );
}

export default AddLink;

然后Todo.js

import React from "react";

function Todo(props) {
  return (
    <div>
      <li>{props.text}</li>
    </div>
  );
}

export default Todo;

任何帮助将不胜感激。

有一个 index 作为 Array.map 回调函数的第二个参数

您可以将它用作渲染的关键,如果您不对列表进行任何重新排序,这是安全的。

{
  todos.map((todo, index) => (
    <Todo key={index} todo={todo} />
  ));
}

如果您想拥有列表的实际键,请尝试 uuid 库,并在添加新的待办事项时生成一个键。

像这样:

import { v4 as uuidv4 } from 'uuid';

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

  console.log("clicked");

  db.collection("links").add({
    id: uuidv4(),  //<-- Add random unique key to your todo item
    todo: input,
    timestamp: firebase.firestore.FieldValue.serverTimestamp()
  });
  setInput("");
};