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>);
}
Let's focus on the
useEffect. In there you added a listener that the callback function isonClick. TheonClickfunction is declared withisShown: falseat the first. So theonClickwill be something like that:So when you click on the button, the
isShownvalue will be changed totruebut theonClickfunction 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:onClickfuntion to not to depend on theisShownstate like this:onClickchanges. For this solution, to avoid the infinit rerenders, you need to memoize theonClickfunction or move the function in the body of the useEffect:OR