React hooks - 动态添加和删除组件。删除问题

React hooks - Dynamically adding and deleting component. Delete problem

已提供 CODESANDBOX 链接!

应用创意的简短摘要: 在线考试应用程序包含两个组件:examform 和 question。和上下文组件:考试。 examform 包含用户动态添加的所有问题。 用户还可以删除问题。每个问题都有一个唯一的 ID。

预期功能: 问题存储在考试上下文数组中,可以通过考试表格和问题访问。 所以这里的想法是,一旦用户单击问题的删除按钮,该问题将通过使用其 id 从上下文数组中删除,从而反映在 examform 组件上的更改。

问题: 假设用户添加了 3 个问题。 如果用户在第二个问题上单击删除,则第三个问题将被删除,第二个问题将具有第三个问题的 ID。如果他点击第一个,第二个将被删除。 更奇怪的是,用户在最后一个问题(比如第 3 个)上点击删除,那个确切的问题将被删除。

我只想在不影响数组其他元素的情况下删除用户点击的问题。

请先查看代码再做假设,谢谢。

CODESANDBOX LINK

为了演示目的,我更改了原始代码和问题,并删除了大部分样式。

一些问题

  1. 每个问题的单选组名称都需要一个唯一的“名称”属性,因为在任何问题上选择任何单选项目都会影响另一个。

解决方案:将 id 属性值附加到 name 属性以创建每个问题的唯一名称组

<input type="radio" name={`sport_${id}`} value="soccer" />
  1. 从问题中删除问题的逻辑不应存在于问题本身。

可能的解决方案:提供一种方法,卡片使用其 id 调用该方法以将其自身从数组中删除(参见下面的代码)

  1. 您物品的渲染有点奇怪。而是将数据存储在数组中,并在 return 方法中处理渲染。 不要忘记你的钥匙道具,否则你的选择将会丢失(最好也将其存储在状态中)

exam.js

export const ExamProvider = ({ children }) => {
  const [questions, setQuestions] = useState([]);

  const removeQuestion = (id) => {
    setQuestions((questions) => questions.filter((q) => q.id !== id));
  };

  return (
    <Exam.Provider
      value={{
        questions,
        setQuestions,
        removeQuestion
      }}
    >
      {children}
    </Exam.Provider>
  );
};

Question.js

const Question = ({ i, id}) => {
  const { removeQuestion } = useContext(Exam);

  return (
    <div className="q-main">
      {id}
      <div className="q-title">
        <h4>Which sport are you interested in the most?</h4>
        <div className="options">
          1. Soccer
          <input type="radio" name={`sport_${id}`} value="soccer" />
          2. Basketball
          <input type="radio" name={`sport_${id}`} value="basketball" />
          3. Bjj
          <input type="radio" name={`sport_${id}`} value="bjj" />
          4. MMA
          <input type="radio" name={`sport_${id}`} value="mma" />
        </div>
        <div className="name">
          Write your name:
          <input type="text" />
        </div>
      </div>
      <div className="delete">
        <button className="deletebtn" onClick={() => removeQuestion(id)}>
          Delete
        </button>
      </div>
    </div>
  );
};

export default Question;

ExamForm.js

import React, { useState, useContext } from "react";
import { Exam } from "../contexts/exam";
import uniqid from "uniqid";
import { IoIosAddCircle } from "react-icons/io";
import Question from "./Question";

const ExamForm = () => {
  const exam = useContext(Exam);

  const addQ = () => {
    const id = uniqid();
    exam.setQuestions((questions) => [
      ...questions,
      {
        id: id
      }
    ]);
  };

  return (
    <div className="form-main">
      <button onClick={addQ} className="addqcs">
        <IoIosAddCircle className="addicon" size={65} color="#0089d6" />
      </button>
      {exam.questions.map((q) => {
        return <Question key={q.id} i={exam.questions.length + 1} id={q.id} />;
      })}
    </div>
  );
};

export default ExamForm;

CodeSandbox