我正在构建一个 React 测验应用程序,一旦所有答案都正确或用户失去所有生命,就会出现一个模式。当用户失去所有生命时,模式可以正常工作。但是,当用户正确回答所有 10 个问题时,模式会按预期打开。但是,当用户单击关闭模式后,它会立即再次出现。它确实在第二次单击时关闭,这令人困惑。什么可能导致错误发生?
const handleModalClose = () => {
setShowModal(false);
setCorrectAnswersCount(0);
};
const Modal = ({ correctAnswersCount, onClose, showConfetti }) => {
const modalRef = useRef();
useEffect(() => {
if (correctAnswersCount >= 9) {
confetti({
particleCount: 100,
spread: 70,
origin: { y: 0.6 },
});
}
}, [correctAnswersCount, showConfetti]);
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" ref={modalRef}>
{correctAnswersCount > 9 && (
<h2>Congrats! You've found all the correct answers!</h2>
)}
<h3>
<b>Score</b>
</h3>
<div className="answer-progress-container">
<div className="answer-progress">
<div
className="answer-progress-bar"
style={{ width: `${(correctAnswersCount / 10) * 100}%` }}
>
{correctAnswersCount}/10
</div>
</div>
<p className="streak-p">Current Streak: {streakCounter}</p>
</div>
</div>
<button className="modal-close" onClick={onClose}>
x
</button>
我称之为模态的部分;
const handleLivesChange = () => {
if (lives === 1) {
showAlertWithTimeout("Yalnızca 1 hakkınız kaldı!");
} else if (lives === 0) {
setLose("Kaybettiniz...");
const element = document.getElementById("lose");
const element2 = document.getElementById("inputs");
if (element) {
element.animate(
[
{ transform: "translateY(10px)" },
{ transform: "translateY(-20px)" },
{ transform: "translateY(10px)" },
],
{
duration: 1000,
iterations: Infinity,
}
);
}
if (element2) {
element2.style.display = "none";
}
setShowRevealAll(true);
setShowModal(true);
}
};
const checkAnswer = (ans) => {
if (givenCorrectAnswers.has(ans)) {
return;
}
let isCorrect = false;
localStorage.setItem("isChangeable", "false");
switch (ans) {
case responseData["answer1"]:
correctlbl1(responseData["answer1"]);
flashGreen("1");
break;
case responseData["answer2"]:
correctlbl2(responseData["answer2"]);
flashGreen("2");
break;
case responseData["answer3"]:
correctlbl3(responseData["answer3"]);
flashGreen("3");
break;
case responseData["answer4"]:
correctlbl4(responseData["answer4"]);
flashGreen("4");
break;
case responseData["answer5"]:
correctlbl5(responseData["answer5"]);
flashGreen("5");
break;
case responseData["answer6"]:
correctlbl6(responseData["answer6"]);
flashGreen("6");
break;
case responseData["answer7"]:
correctlbl7(responseData["answer7"]);
flashGreen("7");
break;
case responseData["answer8"]:
correctlbl8(responseData["answer8"]);
flashGreen("8");
break;
case responseData["answer9"]:
correctlbl9(responseData["answer9"]);
flashGreen("9");
break;
case responseData["answer10"]:
correctlbl10(responseData["answer10"]);
flashGreen("10");
break;
default:
if (ans.trim() !== "") {
setLives((prevLives) => prevLives - 1);
console.log(lives);
for (let i = 1; i <= 10; i++) {
document.getElementById(`${i}`).style.background = "#ff0000";
}
setTimeout(() => {
for (let i = 1; i <= 10; i++) {
document.getElementById(`${i}`).style.background =
"linear-gradient(90deg, #e6fdcc 0%, #e0fdff 100%)";
}
}, 1000);
handleLivesChange();
}
}
if (isCorrect) {
const updatedCorrectAnswers = new Set(givenCorrectAnswers).add(ans);
setGivenCorrectAnswers(updatedCorrectAnswers);
if (updatedCorrectAnswers.size === 10) {
console.log("win");
setShowModal(true);
handleWin();
streak();
}
}
setValue("");
};
组件 Modal 内的任何代码部分都不可能因出现两次而导致此错误。下面是这个结论的推理。
因此调用站点应该是失败的唯一原因。除了以下语句之外,该组件还必须在调用站点的其他位置呈现。
{showModal && <Modal isOpen={showModal} onClose={handleModalClose} />}
请再次检查此方向的调用站点。
请参阅下面基于同一组件的示例代码。它不存在报告的问题。需要重复的是,以下代码中唯一的更改是调用站点。下面的调用站点渲染组件的次数不超过一次。
请注意,为了使该示例更加清晰,示例代码中使用的状态 modalDismissed 仅用于显示警报。它在代码中不再有任何相关性。
App.js
import { useState, useRef, useEffect } from 'react';
export default function App() {
const [showModal, setShowModal] = useState(false);
const [modalDismissed, setModalDismissed] = useState(false);
const handleModalClose = () => {
setShowModal(false);
setModalDismissed(true);
};
function handleModalShow() {
if (modalDismissed) {
alert('Model has been shown already once');
return;
}
setShowModal(true);
}
return (
<>
<button onClick={handleModalShow}>Show Modal Once</button>
{showModal && <Modal isOpen={showModal} onClose={handleModalClose} />}
</>
);
}
const Modal = ({ isOpen, onClose }) => {
const correctAnswersCount = 0;
const streakCounter = 0;
const modalRef = useRef();
useEffect(() => {
const handleClickOutside = (event) => {
if (modalRef.current && !modalRef.current.contains(event.target)) {
onClose();
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [onClose]);
if (!isOpen) return null;
if (correctAnswersCount >= 9) {
confetti({
particleCount: 100,
spread: 70,
origin: { y: 0.6 },
});
}
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" ref={modalRef}>
{correctAnswersCount > 9 && (
<h2>Congrats! You've found all the correct answers!</h2>
)}
<h3>
<b>Score</b>
</h3>
<div className="answer-progress-container">
<div className="answer-progress">
<div
className="answer-progress-bar"
style={{ width: `${(correctAnswersCount / 10) * 100}%` }}
>
{correctAnswersCount}/10
</div>
</div>
<p className="streak-p">Current Streak: {streakCounter}</p>
</div>
</div>
<button className="modal-close" onClick={onClose}>
x
</button>
</div>
);
};
试运行:
a) 加载应用程序时
b) 第一次单击按钮时
c) 通过单击按钮 X
关闭模态框d) 第二次单击按钮时