Skip to content

Instantly share code, notes, and snippets.

@koistya

koistya/App.js

Last active Jul 22, 2021
Embed
What would you like to do?
How to add `onscroll` event in ReactJS component
import React from 'react';
let lastScrollY = 0;
let ticking = false;
class App extends React.Component {
componentDidMount() {
window.addEventListener('scroll', this.handleScroll, true);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
nav = React.createRef();
handleScroll = () => {
lastScrollY = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(() => {
this.nav.current.style.top = `${lastScrollY}px`;
ticking = false;
});
ticking = true;
}
};
render() {
return (
<div>
<nav ref={this.nav}>
</nav>
<div>
);
}
}
export default App;
@koistya

This comment has been minimized.

Copy link
Owner Author

@koistya koistya commented Aug 4, 2015

@Peege151

This comment has been minimized.

Copy link

@Peege151 Peege151 commented Sep 8, 2015

this didn't work for me. I tried console logging inside the handleScroll and it never fired.

@polkovnikov-ph

This comment has been minimized.

Copy link

@polkovnikov-ph polkovnikov-ph commented Sep 14, 2015

What's wrong with builtin onScroll event?

@neptunian

This comment has been minimized.

Copy link

@neptunian neptunian commented Oct 20, 2015

Yes, how does one use React's built in onScroll event?

@arturd-softgrad

This comment has been minimized.

Copy link

@arturd-softgrad arturd-softgrad commented Dec 27, 2015

this didn't work for me.

@barsukov

This comment has been minimized.

Copy link

@barsukov barsukov commented Dec 27, 2015

me too :(

@blackcater

This comment has been minimized.

Copy link

@blackcater blackcater commented Sep 12, 2016

I used React@15.3.1

I tried console logging inside the handleScroll. it never fired. I'm at a loss

@ffxsam

This comment has been minimized.

Copy link

@ffxsam ffxsam commented Sep 22, 2016

This solution works well for me:

(the styles.pane div is a fixed size with overflowY: 'auto', and its child (thumbs) is the content to be scrolled)

  paneDidMount = (node) => {
    if (node) {
      node.addEventListener('scroll', () => console.log('scroll!'));
    }
  };

  renderMediaBrowser = () => {
    if (!this.state.open) return null;

    return <div style={styles.mediaBrowserContainer}>
      <h2 style={styles.dialogTitle}>Media Library</h2>

      <div ref={this.paneDidMount} style={styles.pane}>
        <div style={styles.thumbs}>
          {this.renderImages()}
        </div>
      </div>
    </div>
  };
@andyfaizan

This comment has been minimized.

Copy link

@andyfaizan andyfaizan commented Dec 12, 2016

@ffxsam Your solution worked for me. Thanks!

@j6k4m8

This comment has been minimized.

Copy link

@j6k4m8 j6k4m8 commented May 5, 2017

To those that are having difficulty getting handleScroll to fire:

Try adding this.handleScroll = this.handleScroll.bind(this); to your constructor for that Component. That should make sure that you can call this.handleScroll from the lifecycle functions.

@jylopez

This comment has been minimized.

Copy link

@jylopez jylopez commented Sep 5, 2017

This worked for me:

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

componentDidMount() {
  window.addEventListener('scroll', this.handleScroll);
};

componentWillUnmount() {
  window.removeEventListener('scroll', this.handleScroll);
};

handleScroll(event) {
  console.log('the scroll things', event)
};
@haianhnc

This comment has been minimized.

Copy link

@haianhnc haianhnc commented Oct 2, 2017

@jylopez
thanks bro.

@LyzioOh

This comment has been minimized.

Copy link

@LyzioOh LyzioOh commented Oct 29, 2017

@jylopez That a perfect Simple React Solution. +1 +1 +1 Thanks

@LyzioOh

This comment has been minimized.

Copy link

@LyzioOh LyzioOh commented Oct 29, 2017

Hi @j6k4m8 , this.handleScroll = this.handleScroll.bind(this); Work very well with the traditionnal method declaration Syntax

constructor(props) {
  super(props);
  this.handleScroll = this.handleScroll.bind(this);
}
handleScroll(event) {
  console.log('the scroll things', event)
};

In case you're interested by making you're constructor more dry you could also use the ES6 fat arrow syntax.

constructor(props) {
  super(props);
}
handleScroll = (event) =>  {
  console.log('the scroll things', event)
};

Fat arrow automatically bind this to the method, allowing shorter constructor. Especially when you have a lot of methods.

@mehmetnyarar

This comment has been minimized.

Copy link

@mehmetnyarar mehmetnyarar commented Jan 29, 2018

@jylopez, worked for me too, thanks!

@hnoor

This comment has been minimized.

Copy link

@hnoor hnoor commented Mar 14, 2018

@jylopez worked perfectly for me. thank you so much!

@Lynn0108

This comment has been minimized.

Copy link

@Lynn0108 Lynn0108 commented Jun 14, 2018

@ffxsam your solution works for me ~thank you a lot

@billyma128

This comment has been minimized.

Copy link

@billyma128 billyma128 commented Aug 8, 2018

componentDidMount() {
    // $FlowFixMe
    const node = this.hscroll;
    if (node) {
      node.addEventListener('scroll', e => {
        window.requestAnimationFrame(() => {
          this.setState({ fixed: node.scrollTop > 10 });
        });
      });
    }
  }

componentWillUnmount() {
    // $FlowFixMe
    this.hscroll.removeEventListener('scroll');
  }

render() {
    return (
      // $FlowFixMe
      <Container innerRef={comp => (this.hscroll = comp)}>
@a-m-dev

This comment has been minimized.

Copy link

@a-m-dev a-m-dev commented Aug 20, 2018

this is my solution :

componentDidMount = () => {
   // hadling cover parallax 
    window.addEventListener('scroll', this.handleOnScroll)
}

componentWillUnmount = () => {
    window.removeEventListener('scroll', this.handleOnScroll)
}

// handle onScroll event
handleOnScroll = () => {
    // console.log(this.coverRef.current.height)
    const wScroll = window.scrollY
    this.coverGradRef.current.style.cssText = `transform: translate(0px , -${wScroll/40}%)`
    // console.log(window.scrollY)
}

coverGradRef is a ref that is in my component's constructor and i pass that to child component, it works pretty smooth so far

and one more thing
after this.coverGradRef.current.style you can add cssText and add what every property you want like pure css , if you don't like that you can use something like this.coverGradRef.current.style.top = '10px' and instead of top you can put any valid css property

@vishma9

This comment has been minimized.

Copy link

@vishma9 vishma9 commented Sep 12, 2018

componentDidMount(){
document.addEventListener('scroll', this.handleScroll, true);
}
handleScroll = () => {
console.log('scrolling ...');
}

@venoms

This comment has been minimized.

Copy link

@venoms venoms commented Sep 17, 2018

Note however that input events and animation frames are fired at about the same rate and therefore the optimization below is often unnecessary.

https://developer.mozilla.org/en-US/docs/Web/Events/scroll#Example

@kenadian

This comment has been minimized.

Copy link

@kenadian kenadian commented Sep 26, 2018

Hi @jylopez This is what I needed. Thanks! Appreciated the ES6 tip from @EEtancelin. I like not having to add the bindings in the constructor. Good stuff!

@MarvelMoe

This comment has been minimized.

Copy link

@MarvelMoe MarvelMoe commented Sep 28, 2018

Good stuff @jylopez. Has anyone had any issue with the scroll event not firing on mobile. The touchmove event is what native js uses and I see react has onTouchMove but that is react native specific.

@avatar31

This comment has been minimized.

Copy link

@avatar31 avatar31 commented Nov 3, 2018

@jylopez Thank you so much.. it is working fine

@Mazuh

This comment has been minimized.

Copy link

@Mazuh Mazuh commented Jan 9, 2019

@ffxsam solution worked fine for me too.

@didiraja

This comment has been minimized.

Copy link

@didiraja didiraja commented Jan 21, 2019

@jylopez @EEtancelin best solutions, thx!

@victorpunkd

This comment has been minimized.

Copy link

@victorpunkd victorpunkd commented Jan 28, 2019

solved my problem thanks

@paintedbicycle

This comment has been minimized.

Copy link

@paintedbicycle paintedbicycle commented Feb 5, 2019

If anyone is thinking they are going crazy that it's not working for them, while everyone else is piling on saying it does, try this:

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, true);
  }

Note, the third argument of "true".

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

@dp21g

This comment has been minimized.

Copy link

@dp21g dp21g commented Feb 18, 2019

@paintedbicycle thank you! now it works.

@jerzabek

This comment has been minimized.

Copy link

@jerzabek jerzabek commented Feb 19, 2019

If anyone is thinking they are going crazy that it's not working for them, while everyone else is piling on saying it does, try this:

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, true);
  }

Note, the third argument of "true".

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

Worked for me!

@daniloprates

This comment has been minimized.

Copy link

@daniloprates daniloprates commented Jun 3, 2019

window.addEventListener('scroll', this.handleScroll, true);

Thanks!

@sovietski

This comment has been minimized.

Copy link

@sovietski sovietski commented Jun 6, 2019

@paintedbicycle Thank you!! This worked for me

@miguelespinoza

This comment has been minimized.

Copy link

@miguelespinoza miguelespinoza commented Jun 10, 2019

Thanks this is exactly what I needed to do for a ShadowDOM supported div that used onScroll.
Turns out ShadowDOM does not support scroll listener, it's essentially blocked.

What I did was:

const listNode = ReactDOM.findDOMNode(this.list);
listNode.addEventListener('scroll', this.handleScroll);

and it worked! 🎉

@sushantlp

This comment has been minimized.

Copy link

@sushantlp sushantlp commented Aug 2, 2019

If anyone is thinking they are going crazy that it's not working for them, while everyone else is piling on saying it does, try this:

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll, true);
  }

Note, the third argument of "true".

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

Worked for me

@Jesse-efe

This comment has been minimized.

Copy link

@Jesse-efe Jesse-efe commented Jul 31, 2020

thank you very much @paintedbicycle

@raheemazeezabiodun

This comment has been minimized.

Copy link

@raheemazeezabiodun raheemazeezabiodun commented Aug 4, 2020

This worked for me:

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

componentDidMount() {
  window.addEventListener('scroll', this.handleScroll);
};

componentWillUnmount() {
  window.removeEventListener('scroll', this.handleScroll);
};

handleScroll(event) {
  console.log('the scroll things', event)
};

your solution worked for me. Thank you for this

@koistya

This comment has been minimized.

Copy link
Owner Author

@koistya koistya commented Aug 4, 2020

@raheemazeezabiodun Note, that if you use an arrow function syntax for declaring custom handlers, you won't need to bind them to this inside of a constructor function:

constructor(props) {
  supert(props);
  this.handleScroll = this.handleScroll.bind(this);
}

handleScroll(event) { ... };

vs

handleScroll = (event) => { ... };
@Random-Black-Coder

This comment has been minimized.

Copy link

@Random-Black-Coder Random-Black-Coder commented Feb 11, 2021

Is anyone having issues with the event returning as undefined?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment