I’m trying to build a tourism app using Next.js, and across the Wilayas Component I stumbled into a very weird bug, so inside the component I fetch an svg map, for each zone of the svg map I add an event listener through a useEffect as you can see down below, the event should cause an animation of sliding which works as you can see over here Wilayas Sliding
But if you open the console you’ll be able to see hello displaying from console.log i put in the useEffect to debug my app, with each click it increments but rather with one, it keeps doubling, so to say i you click once, hello is displayed once, if you click twice it’s displayed 3 times, if you click four times you get Hello 15 times meaning 15 re-renders and as you click this keeps escalating to a point causing the website to block!
My Wilayas Component :
const Wilayas = ({ region }: { region: any }) => {
const [wilayas, setWilayas] = useState<HTMLElement[]>([]);
const [currentIndex, setCurrentIndex] = useState(0);
const [left, setLeft] = useState(0);
const [back, setBack] = useState(false);
const [forward, setForward] = useState(true);
const sectionRef = useRef<HTMLUListElement>(null);
const goBack = () => {
setCurrentIndex(currentIndex - 1);
if (sectionRef.current) {
sectionRef.current.style.transform = `translate(${
left + 27.278566666666666
}vw)`;
}
const updatedWilayas = [...wilayas];
updatedWilayas.forEach((wilaya) => wilaya?.classList.add("lighten"));
updatedWilayas[currentIndex]?.classList.remove("darken");
updatedWilayas[currentIndex - 1]?.classList.add("darken");
updatedWilayas[currentIndex - 1]?.classList.remove("lighten");
setWilayas(() => updatedWilayas);
setLeft(left + 27.278566666666666);
if (currentIndex === 1) {
setBack(false);
} else {
setForward(true);
}
};
const goForward = () => {
setCurrentIndex(currentIndex + 1);
if (sectionRef.current) {
sectionRef.current.style.transform = `translate(${
left - 27.278566666666666
}vw)`;
}
const updatedWilayas = [...wilayas];
updatedWilayas.forEach((wilaya) => wilaya.classList.add("lighten"));
updatedWilayas[currentIndex]?.classList.remove("darken");
updatedWilayas[currentIndex + 1]?.classList.add("darken");
updatedWilayas[currentIndex + 1]?.classList.remove("lighten");
setWilayas(() => updatedWilayas);
setLeft(left - 27.278566666666666);
if (currentIndex === 8) {
setForward(false);
} else {
setBack(true);
}
};
const goToExactRegion = useCallback(
(index: number) => {
setCurrentIndex(index);
const updatedWilayas = [...wilayas];
console.log("hello");
updatedWilayas.forEach((wilaya) => wilaya.classList.add("lighten"));
updatedWilayas[currentIndex]?.classList.remove("darken");
updatedWilayas[index]?.classList.add("darken");
updatedWilayas[index]?.classList.remove("lighten");
if (index < currentIndex) {
sectionRef.current!.style.transform = `translate(${
left + (currentIndex - index) * 27.278566666666666
}vw)`;
if (index === 0) {
setBack(false);
}
setForward(true);
setLeft(left + (currentIndex - index) * 27.278566666666666);
} else if (index > currentIndex) {
sectionRef.current!.style.transform = `translate(${
left - (index - currentIndex) * 27.278566666666666
}vw)`;
if (index === 9) {
setForward(false);
}
setBack(true);
setLeft(left - (index - currentIndex) * 27.278566666666666);
}
setWilayas(() => updatedWilayas);
},
[wilayas]
);
const handleSwitch = (index: number) => () => {
goToExactRegion(index);
};
useEffect(() => {
if (document.getElementById("region") !== null) {
const fetching = async () => {
const response = await fetch(
`https://ik.imagekit.io/vaqzdpz5y/assets/images/${region.id}/3.svg`
);
const svgContent = await response.text();
console.log("hello");
document.getElementById("region")!.innerHTML = svgContent;
document.getElementById("svg2")!.style.width = "100%";
const wilayat = [];
for (let i = 1; i < 11; i++) {
const wilaya = document.getElementById(`${i}`);
if (wilaya) wilayat.push(wilaya);
}
setWilayas(wilayat);
};
fetching();
}
}, []);
useEffect(() => {
const wilayat: HTMLElement[] = [];
for (let i = 1; i < 11; i++) {
const wilaya = document.getElementById(`${i}`);
if (wilaya) {
wilaya.addEventListener("click", handleSwitch(i - 1));
wilayat.push(wilaya);
}
}
return () => {
wilayat.forEach((wilaya, i) => {
wilaya.removeEventListener("click", handleSwitch(i - 1));
});
};
}, [wilayas, handleSwitch]);
return (
<div>
...
<div id="region" className="w-[51.5625vw]"></div>
</div>
)
In the last div i add my SVG Map.
I want to highlight the fact that if you check the Destinations page Destinations Page which has the svg inside the code instead of fetching it, and with adding the same event listeners with the same functions, but in this case using the onClick React prop everything works perfectly fine, and as you might see, i can’t just implement the SVG Map of each region as it’ll result into like 11 files, so I would really appreciate your help!