14

I am trying to prevent window scrolling with e.preventDefault() when a wheel event is fired but browser scrolls no matter what.

<div onWheel={this.handleWheelEvent} >
  <div className='yellow fullpage'>Yellow Page</div>
  <div className='green fullpage'>Green Page</div>
  <div className='blue fullpage'>Yellow Page</div>
</div>

js

handleWheelEvent = e => {
    e.preventDefault();
    e.stopPropagation();
    e.nativeEvent.stopImmediatePropagation();
    // those 3 should prevent browser from scrolling but they don't
}
Femi Oni
  • 796
  • 2
  • 9
  • 25
  • Sorry, didn't realize it was ReactJS not JS. This link should help. https://stackoverflow.com/questions/34790949/react-js-onwheel-bubbling-stoppropagation-not-working – dar Aug 05 '19 at 13:06

4 Answers4

9

I couldn't find a way to prevent scrolling in React events but it's possible to achieve same effect using refs

In constructor:

this.divRef = React.createRef()
this.preventDefault = e => e.preventDefault()

In render:

<div ref={this.divRef} >
  <div className='yellow fullpage'>Yellow Page</div>
  <div className='green fullpage'>Green Page</div>
  <div className='blue fullpage'>Yellow Page</div>
</div>

Adding and removing preventDefault event listener:

componentDidMount () {
    this.divRef.current.addEventListener('wheel', this.preventDefault)
}

componentWillUnmount () {
    this.divRef.current.removeEventListener('wheel', this.preventDefault)
}
Remzi Atay
  • 131
  • 2
  • 9
5

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:

vsync
  • 118,978
  • 58
  • 307
  • 400
-1

You can't use ‍event.preventDefault() inside event onScroll, because preventDefault apply after page scrolled. But you can use prevetDefault on the following events:

  • onWheel
  • onKeydown
  • onPageUp
  • onPageDown
mrghofrani
  • 1,335
  • 2
  • 13
  • 32
-3
<div onWheel={e => e.stopPropagation()}></div>

try this

RomanistHere
  • 795
  • 7
  • 17