Hey there!
Could you tell me what's wrong with this code?
I have a button in my application that toggles the state.
I would like to achieve the same with pressing the spaัebar on the keyboard. And it works only one way. The state changes to false once. And then no reaction.
import { useState, useEffect } from 'react'
const HandleKeypress = () => {
const [itWorks, setItWorks] = useState(true)
useEffect(() => {
document.addEventListener('keypress', (e) => {
if (e.code === 'Space') setItWorks(!itWorks)
})
}, [])
return (
<div>
<p>{itWorks ? 'It works!' : 'It does not'}</p>
<button
onClick={() => setItWorks(!itWorks)}
>Press me</button>
</div>
)
}
export default HandleKeypress
What am I missing? ๐ผ
Top comments (11)
This looks like an issue with stale values inside of
useEffect
.Make this change:
I have created a video on this topic here:
Cheers ๐ป
Thanks Joel! :)
This might work. But haven't tested though.
Thanks Eranda! Seems like it doubles the number of added key listeners with each press and soon the application stops responding.
Which means the answer is to remove keyListeners and clean up useEffect an some point? Not sure how, I've reached the limit of my Hooks understanding ๐
When we add
itWorks
as a dependency to useEffect, It will re-render for each change ofitWorks
value. So here it will cause the number of event listeners to multiply at each change.So as @Vesa Piittinen suggests it is a good idea to remove the listener if you are adding it in the useEffect hook.
Thanks for the insights! With these corrections both methods work indeed!
Is there a reason to prefer one over the other?
Thank you! Makes sense.
You still want to remove the event listener on unmount in the second example though!
Thanks for the explanation! I appreciate it.