I am trying to convert a fairly simple React class component to functional component. Here on document click I want to toggle the isShown
boolean value between true
and false
. But each time onClick
is fired, the value isShown
is always false
, even though it was previously toggled to true
. I do not understand what is going on here and how to fix it?
import React, { useEffect, useState } from 'react';
export default function Popover({}: any) {
const [isShown, setIsShown] = useState(false);
useEffect(() => {
document!.addEventListener('click', onClick);
}, []);
function onClick(e: Event) {
console.log(isShown);
setIsShown(!isShown);
}
return (<div></div>);
}
2
Answers
Let’s focus on the
useEffect
. In there you added a listener that the callback function isonClick
. TheonClick
function is declared withisShown: false
at the first. So theonClick
will be something like that:So when you click on the button, the
isShown
value will be changed totrue
but theonClick
function won’t be declared again for the listener in the useEffect and the callback function of the event listener is the one I explained before. Now, you know the problem and you have two solutions:onClick
funtion to not to depend on theisShown
state like this:onClick
changes. For this solution, to avoid the infinit rerenders, you need to memoize theonClick
function or move the function in the body of the useEffect:OR
I don’t think the event listener is necessary. Why don’t you add an
onClick
attribute to the element that needs to changeisShown
? If it is thediv
then perhaps do something like: