React hooks - 动态添加和删除组件。删除问题
React hooks - Dynamically adding and deleting component. Delete problem
已提供 CODESANDBOX 链接!
应用创意的简短摘要:
在线考试应用程序包含两个组件:examform 和 question。和上下文组件:考试。
examform 包含用户动态添加的所有问题。
用户还可以删除问题。每个问题都有一个唯一的 ID。
预期功能:
问题存储在考试上下文数组中,可以通过考试表格和问题访问。
所以这里的想法是,一旦用户单击问题的删除按钮,该问题将通过使用其 id 从上下文数组中删除,从而反映在 examform 组件上的更改。
问题:
假设用户添加了 3 个问题。
如果用户在第二个问题上单击删除,则第三个问题将被删除,第二个问题将具有第三个问题的 ID。如果他点击第一个,第二个将被删除。
更奇怪的是,用户在最后一个问题(比如第 3 个)上点击删除,那个确切的问题将被删除。
我只想在不影响数组其他元素的情况下删除用户点击的问题。
请先查看代码再做假设,谢谢。
为了演示目的,我更改了原始代码和问题,并删除了大部分样式。
一些问题
- 每个问题的单选组名称都需要一个唯一的“名称”属性,因为在任何问题上选择任何单选项目都会影响另一个。
解决方案:将 id 属性值附加到 name 属性以创建每个问题的唯一名称组
<input type="radio" name={`sport_${id}`} value="soccer" />
- 从问题中删除问题的逻辑不应存在于问题本身。
可能的解决方案:提供一种方法,卡片使用其 id 调用该方法以将其自身从数组中删除(参见下面的代码)
- 您物品的渲染有点奇怪。而是将数据存储在数组中,并在 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 链接!
应用创意的简短摘要: 在线考试应用程序包含两个组件:examform 和 question。和上下文组件:考试。 examform 包含用户动态添加的所有问题。 用户还可以删除问题。每个问题都有一个唯一的 ID。
预期功能: 问题存储在考试上下文数组中,可以通过考试表格和问题访问。 所以这里的想法是,一旦用户单击问题的删除按钮,该问题将通过使用其 id 从上下文数组中删除,从而反映在 examform 组件上的更改。
问题: 假设用户添加了 3 个问题。 如果用户在第二个问题上单击删除,则第三个问题将被删除,第二个问题将具有第三个问题的 ID。如果他点击第一个,第二个将被删除。 更奇怪的是,用户在最后一个问题(比如第 3 个)上点击删除,那个确切的问题将被删除。
我只想在不影响数组其他元素的情况下删除用户点击的问题。
请先查看代码再做假设,谢谢。
为了演示目的,我更改了原始代码和问题,并删除了大部分样式。
一些问题
- 每个问题的单选组名称都需要一个唯一的“名称”属性,因为在任何问题上选择任何单选项目都会影响另一个。
解决方案:将 id 属性值附加到 name 属性以创建每个问题的唯一名称组
<input type="radio" name={`sport_${id}`} value="soccer" />
- 从问题中删除问题的逻辑不应存在于问题本身。
可能的解决方案:提供一种方法,卡片使用其 id 调用该方法以将其自身从数组中删除(参见下面的代码)
- 您物品的渲染有点奇怪。而是将数据存储在数组中,并在 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;