This is a classic menu case, open on a button click, hide in 5 seconds if no activity. We have 2 state variables. open and active, corresponding to two different states = menu is open, and active (being used). I set the open variable using a button click, then in effect I start the 5 second timeout. Now if the user mouseovers the menu,I set the active property to true and try to clear the timeout. But that is not working. Meaning, the timeout var is always null inside the code that is supposed to clear it.
Here is some code to help you understand:
let [open, openMenu] = useState(false)
let [active, activateMenu] = useState(false)
let timer = null;
useEffect(() => {
if(open && !active) {
timer = setTimeout(() => setOpen(false), 5000)
}
if(open && active) {
if(timer) {
clearTimeout(timer)
}
}
}, [open, active])
// Triggered via the UI on a button click
openMenuhandler() {
setOpen(true)
}
// Triggered via the UI on mouseenter
// identifies that the menu is being used, when mouse is over it
setMenuActive() {
activateMenu(true)
}
// Triggered via the UI on mouseleave
setMenuInActive() {
activateMenu(false)
}
// other code here on
Now the timeout is never cleared. The menu hides in 5 seconds, no matter what. Is there another way to do it? I have even tried moving the clearTimeout to the mouseLeave, but even then the timer is null. How to fix this? Please help.
Whenever your component re-renders, timer
variable will be re-declared with an initial value of null
. As a result, when useEffect
hook executes whenever any of its dependency changes, timer
variable is null
.
You can solve the problem by making sure that value of the timer
variable is persisted across re-renders of your component. To persist the value across re-renders, either save the id of the setTimeout
using useRef
hook or save it in the state, i.e. useState
hook.