React binds all events at the root element (not the document
), and the wheel
event is binded internally using true
option, and I quote MDN:
A Boolean that, if true, indicates that the function specified by listener will never call preventDefault(). If a passive listener does call preventDefault(), the user agent will do nothing other than generate a console warning
This is how I did blocked the page from scrolling while using the wheel to affect an input field:
const wheelTimeout = useRef()
const onWheel = e => {
// ... some code I needed ...
// while wheel is moving, do not release the lock
clearTimeout(wheelTimeout.current)
// flag indicating to lock page scrolling (setTimeout returns a number)
wheelTimeout.current = setTimeout(() => {
wheelTimeout.current = false
}, 300)
}
// block the body from scrolling (or any other element)
useEffect(() => {
const cancelWheel = e => wheelTimeout.current && e.preventDefault()
document.body.addEventListener('wheel', cancelWheel, {passive:false})
return () => document.body.removeEventListener('wheel', cancelWheel)
}, [])
Reference discussions: