Asked By: Anonymous
I am trying to use stopPropagation so my dropdown menu will close after I click on any other elements.
When I try to use stopPropagation & updating a boolean state the button re-render the page (which reset the state back to ‘false’) than updating the state to true and it stuck on "true" no matter what.
I wrote a code for an example:
import { useEffect, useState } from "react";
export default function IndexPage() {
const [state, setState] = useState(false);
useEffect(() => {
document.body.addEventListener("click", () => {
setState(false);
});
});
const onButtonClick = (e) => {
e.stopPropagation();
setState(!state);
};
console.log(state);
return (
<div>
<button onClick={onButtonClick}>Click</button>
<h1>{state ? "true" : "false"}</h1>
</div>
);
}
_x000D_
_x000D_
x000D
This problem seems to appear only with Next.js
I wrote the same code with React app and there is no problem.
Next.js codesandbox link
React codesandbox link
Edit:
When you fork the Next.js sandbox project everything is working fine. (and yet it doesn’t solve the problem with my original code).
Anyone knows why is it happening?
Solution
Answered By: Anonymous
I did found a fix for this bug and the first person Who comment me solved this issue.
I add to my code a cleanup for my event listener and it seems to solve the problem.
It seems like cleanup inside useEffect is not just a good practice but a "must".
Because of the cleanup useEffect re-render the page twice and not three times and it prevent it from another render which cause the problem.
Big thanks for anyone tried to help.
The fixed code is:
export default function IndexPage() {
const [state, setState] = useState(false);
useEffect(() => {
window.addEventListener("click", () => setState(false));
return () => window.removeEventListener("click", () => setState(false));
});
const onButtonClick = (e) => {
e.stopPropagation();
setState(!state);
};
console.log(state);
return (
<div>
<button onClick={onButtonClick}>Click</button>
<h1>{state ? "true" : "false"}</h1>
</div>
);
}
_x000D_
_x000D_
x000D
Next.js sandbox link