React Warning non-passive event listener to a scroll-blocking 'touchstart'
Asked Answered
C

4

7

I have a react component with a material-ui Slider. Each time this component renders I get this warning : "Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive"

How can this be fixed?

image of warnings in console

Catastrophism answered 11/12, 2019 at 9:10 Comment(0)
W
6

Many libraries and frameworks add non-passive event listeners by default. Not much you can do about it.. Instead of waiting for a support I Would recommend using highly flexible and configurable passive-events-support package to debug and make event listeners passive without touching 3rd party source code.

First, after installing the package debug the touch and wheel event listeners and their parameters:

import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport({ debug: true })

This should console log all the event listeners

[Passive Events Support] Non-passive Event Listener
  element: div.some-element
  event: 'touchstart'
  handler:
    fn: ƒ (e)
    fnArgument: 'e'
    fnContent: 'console.log(e)'
    fnPrevented: false
  arguments: false

Notice arguments parameter, if it is false, undefined or object without passive parameter inside, this event is what causes your browser to throw a warning and is impacting the scroll performance.

To fix it just use the package and logged information to make this exact event listener as passive:

import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport({
  debug: false,
  // add this one
  listeners: [
    {
      element: 'div.some-element',
      event: 'touchstart'
    }
  ]
})

Be careful tho, event listeners that call preventDefault() should not be marked as passive, but to fix the warning should still have passive parameter with a value of false instead.

By default the package will check if it is prevented from the handler itself, but in case the event listener is prevented from the method called inside the handler, the package loses track of it. To force assign passive: false just pass prevented: true parameter to listeners item:

passiveSupport({
  //...
  listeners: [
    {
      element: 'div.some-element',
      event: 'touchstart',
      prevented: true
    }
  ]
})

For me, this package fixed all the warnings cause by materialize and jquery. Hope it helps you too.

Whisker answered 22/1, 2022 at 9:55 Comment(0)
V
0

Passive event listener has not been supported by React. What you have to do is obtain the ref of the real dom and attach the event listener with {passive:true} as an option. And don't forget to detach the event listener before destroying the component(in the componentWillUnmount actually).

Vitalize answered 11/12, 2019 at 9:36 Comment(7)
Thx for your answer . How do I obtain the ref of the real dom and attach the event listener? I tried adding document.addEventListener('touchstart',{passive:true}) when component mounts ,but did not helpCatastrophism
@Catastrophism Please refer to this doc: reactjs.org/docs/refs-and-the-dom.html. You have to create a ref and assign it to the dom(jsx tag) which you want to assign the event listener.Vitalize
Thank you for your help . I tried : const slider = useRef(null); useEffect(() => { slider.current.addEventListener('touchstart', handleTouchStart, { passive: true }) }, []) But it did not help...I'm I doing something wrong ? to me it looks like the warning is form material-ui Slider.js file - slider.addEventListener('touchstart', handleTouchStart); (when I press on the warning in console this is where I get to....)Catastrophism
@Catastrophism Could you please create an online sample such as codesandbox then I can give you help by checking your code ?Vitalize
the warnings appear in verbose in console. But when I create a sample in CodeSandbox there is no warning.Catastrophism
.I add an image of the warnings I get in console.Catastrophism
It looks like you did not make the event listener be passive successfully. I've mentioned that passive hasn't been supported by React natively. You are able to achieve this by using the traditional way: developer.mozilla.org/en-US/docs/Web/API/EventTarget/….Vitalize
Z
0

you can check the github fork for details (issues #20) on how to fix, below is what it does:

amend lines 132, 134 & 136 of sidenav.js.

Changed from:

this.dragTarget.addEventListener('touchmove', this._handleDragTargetDragBound);
this._overlay.addEventListener('touchmove', this._handleCloseDragBound);
this.el.addEventListener('touchmove', this._handleCloseDragBound);

to:

this.dragTarget.addEventListener('touchmove', this._handleDragTargetDragBound, { passive: true});
this._overlay.addEventListener('touchmove', this._handleCloseDragBound, { passive: true});
this.el.addEventListener('touchmove', this._handleCloseDragBound, { passive: true});
Zena answered 12/4, 2021 at 2:47 Comment(0)
A
0

Just leave this here hopefully for someone will be helpful one day. I was having this error message and as I was searching for a solution for a FramerMotion bug come accross this line of code and not just the issue with FramerMotion disappered but also the annoying chrome [violation] error message.

<script>history.scrollRestoration = "manual"</script>
Appanage answered 4/8, 2024 at 19:14 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.