React: ES6 onScroll never fires

Created on 2 Oct 2015  Â·  20Comments  Â·  Source: facebook/react

I've been trying this out and I can't seem to get it working.

export default class MyPage extends React.Component {
    render () { 
       return <div className='page-wrapper'
          onWheel={(e)=>console.log('WHEEL!!',e)}
          onScroll={(e)=>console.log('SCROLL!!',e)}>
          {... my page content ...}
        </div>;
    }
}

the onWheel fires normally, but the onScroll is not firing. I dunno if I'm missing something or this is a bug.

Thanks!

Most helpful comment

@ddaza Add a true to the end of that window listener to enable capture mode.

All 20 comments

If you're trying to catch scrolls of the whole page, you need to attach a scroll event handler to window by hand. See also #285.

If you're talking about doing something like this?

export default class MyPage extends React.Component {
    componentDidMount() {
       window.addEventListener('scroll', (e)=>console.log(e.target));
    }

    render () { 
       return <div className='page-wrapper' >
          {... my page content ...}
        </div>;
    }
}

I tried that and it didn't work.

I also tried:

export default class MyPage extends React.Component {
    componentDidMount() {
       this.refs.wrapper.getDOMNode().addEventListener('scroll', (e)=>console.log(e.target));
    }

    render () { 
       return <div className='page-wrapper'  ref='wrapper'>
          {... my page content ...}
        </div>;
    }
}

It didn't work either.
I have some parent components that use MyPage, I dunno if it makes a difference.

I meant the former. If that doesn't work, it's hard for me to imagine how it could be a React problem.

Is there a way for me to check what is swallowing the event?

@ddaza Add a true to the end of that window listener to enable capture mode.

Same problem with mine.

constructor(props) {
    super(props);
    this.fireOnScroll = this.fireOnScroll.bind(this);
}

fireOnScroll() {
    console.log('Fire!');
}

componentDidMount() {
    const elem = ReactDOM.findDOMNode(this.refs.elementToFire);
    elem.addEventListener('scroll', this.fireOnScroll);
}

componentWillUnmount() {
    const elem = ReactDOM.findDOMNode(this.refs.elementToFire);
    elem.removeEventListener('scroll', this.fireOnScroll);
}

render() {
    return (
        <div className="div-with-overflow" ref="elementToFire">{this.props.children}</div>
    );
}

The problem is that nothing happens when I scroll over the div above...
_div contains a table_

@admiral96 there are problems with the code you posted, but this a bug tracker not a Q&A - you'll find better help on StackOverflow or something similar.

@admiral96 you can check my implementation of onScroll in my module, it is working.
https://github.com/cht8687/react-listview-sticky-header/blob/master/src/ReactListView.js#L66-L69

thanks

Add a true to the end of that window listener to enable capture mode is working. Thanks @probablyup

@sbenda can you paste your code with true? thanks!

elem.addEventListener('scroll', this.fireOnScroll , true);

@probablyup thank you for the pointer. I struggled with this in a SSR site for 2 days to attach a scroll event and not be able to fire it.

All works now :)

@cht8687 Thanks a lot.I was stuck for 2-3 hours on this issue.cheers

be live

I found onScroll is fired when element which has fixed height and enable scroll ....

I ran into this myself. It’s not a React problem per se, but more understanding which element is responsible for scrolling. Like @sophiebits mentioned prior, if you want to listen to the window as supposed to a React component, you most likely need to manage an event listener yourself.

Here’s what I did, I hope it will help others:

// We need to listen to scroll events on the window so we
// manage an event listener ourselves.
React.useEffect(() => {
  const handleScroll = e => {
    // Do something here ...
  }
  document.addEventListener("scroll", handleScroll, { passive: true })
  return () => {
    // This cleans up the event handler when the component unmounts.
    document.removeEventListener("scroll", handleScroll)
  }
}, [])

More info on the third argument to addEventListener here https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners

still best solution for

elem.addEventListener('scroll', this.fireOnScroll , true);

Does anyone out there in the Universe have a:
Working. Simple. Example. Of. React onScroll.

I'm going to lock this thread because the drive-by comments have stopped adding value.

onScroll fires in React perfectly fine, if you put it on the thing that scrolls:

    <div
      className="App"
      style={{
        height: 100,
        overflow: "scroll",
        border: "1px solid red"
      }}
      onScroll={(e) => {
        // Ignore scroll events on nested divs
        // (this check won't be necessary in React 17)
        if (e.target === e.currentTarget) {
          console.log("scrolling");
        }
      }}
    >
      ...
    </div>

https://codesandbox.io/s/hidden-field-mhi8h

If the thing that scrolls is outside your React tree (e.g. it's window itself), then you need to put it manually on window, like @zaydek did above.

  useEffect(() => {
    function handleScroll(e) {
      console.log("scrolling");
    }
    window.addEventListener("scroll", handleScroll, { passive: true });
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

https://codesandbox.io/s/sharp-sea-48ujf

Despite the downvotes on @sophiebits's https://github.com/facebook/react/issues/5042#issuecomment-145144335, it is correct — if neither of these approaches work, it means you're listening to the wrong thing. For example, maybe your scrollable element is neither the thing you're listening to nor the window, but some div in the middle (maybe even outside a React tree). An easy way to check it is to listen to scroll in the capture phase and log what's being scrolled:

window.addEventListener('scroll', (e) => {
  console.log('scrolling', e.target)
}, { capture: true })

This will subscribe to every single scroll of any nested scrollable, so it's not very useful by itself, but it will tell you which div is responsible for scrolling on your page.

Again, this thread is getting really confused, so I'm locking. If you have a problem file a new issue with a reproducing case.

Was this page helpful?
0 / 5 - 0 ratings