30

I'm trying to add an onScroll event on a table. This is what I've tried:

componentDidMount() {
    ReactDOM.findDOMNode(this.refs.table).addEventListener('scroll', this.listenScrollEvent);
}

componentWillUnmount() {
    ReactDOM.findDOMNode(this.refs.table).removeEventListener('scroll', this.listenScrollEvent);
}

listenScrollEvent() {
    console.log('Scroll event detected!');
}

render() {
    return (
        <table ref="table">
           [...]
        </table>
    )
}

I tried console.log(ReactDOM.findDOMNode(this.refs.table)) and I'm getting the correct result but scroll event is never fired at all. I looked in here but still failed. Any help would be so much appreciated.

4
  • 1
    Is table content overflowing table boundaries? It not, it won't scroll. Commented Sep 5, 2016 at 7:31
  • the container has overflow: auto that means the table is inside a frame(if I'm correct). I don't want to use the window.addEventListener Commented Sep 5, 2016 at 7:45
  • try add display: block to table. Commented Sep 5, 2016 at 8:02
  • 1
    For those who are implementing the same as mine but is using django, try using django-el-pagination. It has paginateOnScroll already. Commented Sep 6, 2016 at 9:07

7 Answers 7

23

You need to bind this to the element in context.

render() {
    return (
        <table ref="table" onScroll={this.listenScrollEvent.bind(this)}>
           [...]
        </table>
    )
}
Sign up to request clarification or add additional context in comments.

4 Comments

If you use ES6 Class for creating component.
I already did at the constructor but still doesn't work. constructor(props) {super(props); this.listenScrollEvent = this.listenScrollEvent.bind(this);}
While this is generally useful, note that the listenScrollEvent method in the original question doesn't do anything with this so binding it is actually unnecessary.
Well this actually helps me for some reason. It is simple and to the point
8

You can use onScroll attribute:

listenScrollEvent() {
    console.log('Scroll event detected!');
}

render() {
    return (
        <table onScroll={this.listenScrollEvent}>
           [...]
        </table>
    )
}

Here is an example: https://jsfiddle.net/81Lujabv/

2 Comments

I thought putting onScroll event on an element is not enabled in react? o_0
I tried changing it to onClick and it works... now back to the problem of onScroll
7

I was looking to do something similar. Adding the event listener to the window instead of the ReactDom.findDOMNode worked for me...

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

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

handleScrollToElement(event) {
    console.log('Fired ' + event)
}

2 Comments

I suspect this is the correct answer even though the asker said he didn't want to use window... in the comments. Yet, in the comments he also failed to answer the first question of whether the table contents are overflowing. I suspect the answer is really "no" since no other answers work for him. He doesn't tell us much about his ultimate goal so I can only guess he's going for a fixed/absolute table that will never scroll except with window. I was having similar trouble at first until I got the hint that scroll only fires on objects that overflow, so I looked it up and, yup, that was it.
you can have more than 1 scrolling component on a window, so not so great.
1

according to React documents(https://reactjs.org/docs/handling-events.html),

React events are named using camelCase, rather than lowercase. You can set attributes as you do with pure HTML.

HTML:

<div onclick="..." onscroll="...">
  ...
</div>

JSX:

<div onClick={...} onScroll={...}>
  ...
</div>

you should create a wrapper block element which has fixed height to enable scroll.

Comments

0

I had been finding a good solution to this problem. The following piece of code is working, where the listener is just on the particular class/div : React version is 16.0.0

First import ReactDOM, import ReactDOM from "react-dom";

Then in the class xyz extends Component section

  constructor(props) {
    super();
    this.state = {
        vPos : 0
    }
    this.listenScrollEvent = this.listenScrollEvent.bind(this);
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this.refs.category_scroll).addEventListener('scroll', this.listenScrollEvent);
  }

  componentWillUnmount() {
      ReactDOM.findDOMNode(this.refs.category_scroll).removeEventListener('scroll', this.listenScrollEvent);
  }

  listenScrollEvent(event) {
    console.log('firee');
    this.setState({
        vPos: event.target.body.scrollTop
    });
  }

After pasting the above functions, in the render() method , whatever you want to name the ref method, you can do so, make sure the same name goes in the findDOMNode as well , i.e, findDOMNode(this.refs.category_scroll):

<div onScroll={this.listenScrollEvent} ref="category_scroll">
...
</div>

.

.

If it's a horizontall scroll, then event.currentTarget.scrollTop works in the listenScrollEvent() function.

Comments

0

In case if you are still struggling with not being able to detect scroll event from a table, try to attach the even listener to the parent component because it may be limiting the height/width of the table.

From:

<div className="max-h-[75vh]">
        <table onScroll={listenScrollEvent}>

To:

<div className="max-h-[75vh]" onScroll={listenScrollEvent}>
        <table>

Note: max-h-[75vh] is a Tailwind style.

Comments

-1

Give this a try, added .bind(this) to this.listenScrollEvent when you pass it to the addEventListener.

   componentDidMount() {
        ReactDOM.findDOMNode(this.refs.table).addEventListener('scroll', this.listenScrollEvent.bind(this));
    }

    componentWillUnmount() {
        ReactDOM.findDOMNode(this.refs.table).removeEventListener('scroll', this.listenScrollEvent.bind(this));
    }

    listenScrollEvent() {
        console.log('Scroll event detected!');
    }

    render() {
        return (
            <table ref="table">
               [...]
            </table>
        )
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.