我正在删除我按下的删除按钮旁边的答案。我正在生成一个答案列表,每个答案旁边都有一个相应的删除按钮。然而,当我按下删除按钮时,最后两个答案总是被删除。我也试过使用拼接方法,但结果是一样的。也许我传递的参数有问题,但我现在真的不确定。
编辑:我发现这部分代码中的处理程序被执行了两次,但是,我找不到这种行为的原因:
{poll.questions.map((questionObj, questionIndex) => (
<div key={questionIndex}>
<h2>
{questionObj.question +
(questionObj.multiChoice
? " - (multiple choice)"
: " - (single choice)")}
<br />
<button onClick={() => handleDeleteQuestion(questionIndex)}>
Delete question
</button>
</h2>
{questionObj.choices.map((choice, choiceIndex) => (
<div key={choiceIndex}>
<input
type="text"
placeholder={`Choice ${choiceIndex + 1}`}
value={choice.text}
onChange={(e) =>
handleAnswerChange(questionIndex, choiceIndex, e.target.value)
}
/>
</div>
))}
<button
onClick={(e) => {
e.stopPropagation(); // Prevent event propagation
handleDeleteAnswer(questionIndex);
}}
>
-
</button>
</div>
))}
完整代码:
import React, { useState } from "react";
function NewPoll() {
const [poll, setPoll] = useState({
name: "",
description: "",
multiChoice: false,
questions: [],
answers: [],
});
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
const newValue = type === "checkbox" ? checked : value;
setPoll((prevPoll) => ({
...prevPoll,
[name]: newValue,
}));
};
const handleMultipleAnswer = () => {
const question = prompt("Enter the multiple-choice question:");
if (question !== null) {
const numAnswers = parseInt(
prompt("Enter the number of possible answers:"),
10
);
if (!isNaN(numAnswers)) {
const newQuestion = {
question,
choices: Array(numAnswers).fill(""), // Initialize with empty strings
multiChoice: true,
};
setPoll((prevPoll) => ({
...prevPoll,
questions: [...prevPoll.questions, newQuestion],
}));
}
}
};
const handleSingleAnswer = () => {
const question = prompt("Enter the single choice question:");
if (question !== null) {
const numAnswers = parseInt(
prompt("Enter the number of possible answers:"),
10
);
if (!isNaN(numAnswers)) {
const newQuestion = {
question,
choices: Array(numAnswers).fill(""), // Initialize with empty strings
multiChoice: false,
};
setPoll((prevPoll) => ({
...prevPoll,
questions: [...prevPoll.questions, newQuestion],
}));
}
}
};
/* const [checkedState, setCheckedState] = useState(
new Array(poll.questions.length).fill(false)
);
const handleChoiceChange = (position) => {
const updatedCheckedState = checkedState.map((item, choiceIndex) =>
choiceIndex === position ? !item : item
);
setCheckedState(updatedCheckedState);
};
*/
const handleAnswerChange = (questionIndex, choiceIndex, newText) => {
setPoll((prevPoll) => {
const updatedQuestions = [...prevPoll.questions];
updatedQuestions[questionIndex].choices[choiceIndex] = newText;
return {
...prevPoll,
questions: updatedQuestions,
};
});
};
const handleDeleteQuestion = (questionIndex) => {
setPoll((prevPoll) => {
const updatedQuestions = [...prevPoll.questions];
const deletedQuestion = updatedQuestions.splice(questionIndex, 1)[0];
deletedQuestion.choices = [];
return {
...prevPoll,
questions: updatedQuestions,
};
});
};
const handleDeleteAnswer = (questionIndex) => {
setPoll((prevPoll) => {
const updatedQuestions = [...prevPoll.questions];
const lastQuestion = updatedQuestions[questionIndex];
if (lastQuestion.choices.length > 0) {
lastQuestion.choices.pop(); // Remove the last choice
}
console.log("hey");
return {
...prevPoll,
questions: updatedQuestions,
};
});
};
return (
<>
<h1>Enter poll name:</h1>
<br />
<input
type="text"
name="name"
value={poll.name}
onChange={handleInputChange}
/>
<h1>Enter a description:</h1>
<textarea
rows="10"
cols="50"
name="description"
value={poll.description}
onChange={handleInputChange}
></textarea>{" "}
<br />
<button onClick={handleMultipleAnswer}>
Create a question with multiple answers
</button>
<button onClick={handleSingleAnswer}>
Create a question with a single answer
</button>
{poll.questions.map((questionObj, questionIndex) => (
<div key={questionIndex}>
<h2>
{questionObj.question +
(questionObj.multiChoice
? " - (multiple choice)"
: " - (single choice)")}
<br />
<button onClick={() => handleDeleteQuestion(questionIndex)}>
Delete question
</button>
</h2>
{questionObj.choices.map((choice, choiceIndex) => (
<div key={choiceIndex}>
<input
type="text"
placeholder={`Choice ${choiceIndex + 1}`}
value={choice.text}
onChange={(e) =>
handleAnswerChange(questionIndex, choiceIndex, e.target.value)
}
/>
</div>
))}
<button
onClick={(e) => {
e.stopPropagation(); // Prevent event propagation
handleDeleteAnswer(questionIndex);
}}
>
-
</button>
</div>
))}
<br />
<button> Create a new poll </button>
</>
);
}
export default NewPoll;
这是我到目前为止试过的代码
2条答案
按热度按时间yrdbyhpb1#
您的
handleDeleteAnswer
触发了一次,但您的setPoll
回调触发了两次。您可以通过在handleDeleteAnswer
的最开始放置一个console.log
,并在setPoll
回调的最开始放置另一个console.log
来验证这一点。我相信这是由于在开发中使用了React.StrictMode
。参见https://github.com/facebook/react/issues/12856为了解决这个问题,我建议为你的每个问题和选择分配唯一的ID,然后使用这些ID来确定你想要删除的项目,而不是使用索引。即使
setPoll
调用触发了两次,第一次删除的ID在第二次时也将不再存在-它是幂等的。举一个简单的例子,我在你的代码中修改并更新了它,这样在你初始化
choices
数组的地方,我现在把它Map到一个包含ID的对象:在呈现您的选择时,将
choice.id
传入handleDeleteAnswer
函数,而不是选择的索引。然后更新
handleDeleteAnswer
函数,使用choiceId来定位要删除的选项:顺便说一下,在这种情况下,应该避免使用数组索引作为元素键;指数可能会发生变化。这将是使用ID的另一个候选者。
zpf6vheq2#
嗨,我想你的问题是你有10个盒子和1个按钮来关闭盒子,或者你有10个盒子和10个关闭/删除按钮?
如果你有10个盒子,并且在每个盒子里都有一个删除按钮,你可以使用“closet”,Closest将查找父元素作为选择器。这里是一个例子。
否则,你也可以使用'事件委托',如果你问谷歌或最接近你会发现很多例子,也许这将有助于你找到最好的方法^^
我希望我没有错过这个问题XD