I’m building a React quiz app where a modal should appear once all answers are correct or when the user loses all the lives. However, the modal opens twice instead of once despite my attempts to control the state. I tried managing the modal display using a state variable showModal. I’ve also attempted adding a flag to control it but the issue persists. Added some console.log and i saw that once i open the page the modal is being rendered multiple times already. What could be causing this issue?
const handleModalClose = () => {
setShowModal(false);
};
const Modal = ({ isOpen, onClose }) => {
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>
The part where i call the modal, hope it’s clearer now;
{console.log("Modal rendered")}
{showModal && (
<Modal
isOpen={showModal}
onClose={handleModalClose}
/>
)}
2
Answers
One option would be to use
useEffect
to check thecorrectAnswersCount
andlives
:So,
There is no chance for any part of the code inside the component Modal to cause this bug by appearing twice. Below is the reasoning for this conclusion.
Therefore the calling site should be the only cause of failure. This component must be rendered somewhere else in the calling site besides the following statement.
Please check again the calling site in this direction.
Please see below a sample code based on the same component. It does not have the reported issue. And it is to repeat that the only change in the below code is the calling site. The calling site below does not have rendered the component not more than once.
Please note that the state modalDismissed used in the sample code is used just for an alert to be shown, for the sake of clarity of this sample. It does not have any more relevance in the code.
App.js
Test run:
a) On load of the App
b) On the first click of the button
c) On dismissing the Modal by clicking the button X
d) On the second click of the button