jimmy
jimmy

Reputation: 1719

How to detect the scrolling to bottom in react

I tried to do something when user is scroll to the bottom, and following is what I did in react component.

Notices that it is work, but the weird issue is even if I add a debounce the doSomething function still fired twice when scroll reach the bottom.

I have to chage the delay from 500 to 3000 or more to avoid the issue happen. Why is that, and how to fix this problem?

componentDidMount() {
    window.addEventListener('scroll', _.debounce(this.handleScroll.bind(this), 500));
}

componentWillUnmount() {
    window.removeEventListener('scroll', _.debounce(this.handleScroll.bind(this), 500));
}

handleScroll() {
    const documentElement = document.documentElement;
    const isScrollToBottom = documentElement.clientHeight + documentElement.scrollTop === documentElement.scrollHeight;

    if (isScrollToBottom) {
        this.doSomething()
    }
}

doSomething(){
    // do something
}

Upvotes: 1

Views: 521

Answers (3)

jimmy
jimmy

Reputation: 1719

If you are a mac user, the trackpad or magic mouse may cause bounce when you do a quick srolling.

Sometimes the bounce will continue for a long time (it could be two seconds or more), it depends on how quick you slick your trackpad.

So if you tried to use setTimeout to async debounce this issue, it will cost a lot of delay time.

I haven't execly fix the issue yet. But if your doSomething() is an async function, at lease you can call the function in the right order.

My way to 'temporarily' slove this problem is very similar to the Bhojendra Rauniyar's answer.

state = {
  isScrolled: false
}

doSomething(){
    // set isScrolled = false, when async function is done
}

if (isScrollToBottom && !isScrolled) {
  this.setDelay(doSomething, 500)
}

setDelay(callback, time) {
    this.setState({ isScrolled: true });
    setTimeout(
        () => {
            callback();
        },
        time,
    );
}

Upvotes: 0

Bhojendra Rauniyar
Bhojendra Rauniyar

Reputation: 85545

I was resolving exactly similar problem while I saw this question. Here's how I did it:

Set the initial state to flag if doSomething is called:

state = {
  isScrolled: false
}

Call doSomething only if it is not scrolled:

if (!isScrolled) {
  this.doSomething()
  // set scrolled to true
  this.setState({isScrolled: true})
}

In your case, you can combine the condition:

if (isScrollToBottom && !isScrolled) {

To be frankly, I tried several things to resolve this. But I resolved it after an hour, and your post was still in my window tab. Hope, you like this approach as well. This way, you even do not need to use debounce method.


BTW, I was using hooks:

const [isScrolled, setIsScrolled] = useState(false)

useEffect(() => {
  doSomething()
  setIsScrolled(true)
},[isScrolled])

Upvotes: 1

Smail Galijasevic
Smail Galijasevic

Reputation: 803

Try defining your debouce function a separate handler

handler = _.debounce(() => {
  console.log('foo');
}, 100

then use this handler is your addEventlistener and removeEventListener

Upvotes: 0

Related Questions