Aaron Balthaser
Aaron Balthaser

Reputation: 2622

Calling a method when scroll starts

I have a react component that uses scroll events. When the scroll event is called it basically runs the handler as expected. However I need to be able to call a method once when the scroll events begin to fire. I understand the idea of a debounce method which would fire when the scroll stops, but I need to find a way to fire once when scrolling begins. (For sure NO jQuery can be used).

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

    this.setState({
        // sets some state which is compared in a shouldComponentUpdate
    });
}

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

shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
}

The handler seen below runs some code:

onScroll() {
    this.scrollTop = document.documentElement.scrollTop;
    this.update();
}

But I need a function that runs once:

scrollStart() {

}

I would love to say I have tried something but unfortunately I have no ideas. Any assist would be greatly appreciated.

Upvotes: 4

Views: 9637

Answers (4)

Nolo
Nolo

Reputation: 886

There is no scrollstart event in javascript, however you can register pointer events on the parent element and scroll events on the target element.

Then, for example, in the pointerdown callback reset a variable that gets set when scrolling starts.

If you want you can even dispatch a custom "scrollstart" event on the target when the scroll event is triggered and var scrolling is not set.

For document.body you can listen for pointer ( or touch or mouse ) events on window.

Upvotes: 0

Tholle
Tholle

Reputation: 112777

There is no real scrolling state in the browser; the scroll event happens, and then it's over.

You could e.g. create a new timeout each time the user scrolls and set your own scrolling state to false if the user hasn't scrolled until the timeout function is run.

Example

class App extends React.Component {
  timeout = null;
  state = { isScrolling: false };

  componentDidMount() {
    window.addEventListener("scroll", this.onScroll);
  }

  componentWillUnmount() {
    window.removeEventListener("scroll", this.onScroll);
  }

  onScroll = () => {
    clearTimeout(this.timeout);
    const { isScrolling } = this.state;

    if (!isScrolling) {
      this.setState({ isScrolling: true });
    }

    this.timeout = setTimeout(() => {
      this.setState({ isScrolling: false });
    }, 200);
  };

  render() {
    return (
      <div
        style={{
          width: 200,
          height: 1000,
          background: this.state.isScrolling ? "green" : "red"
        }}
      />
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="root"></div>

Upvotes: 6

Daniel Gimenez
Daniel Gimenez

Reputation: 196

For this you could define a static variable and when the scroll starts, put true in the variable and enter a while that keeps checking if the scrool continues. Using this logic, you may be able to do something.

Upvotes: -1

Sam Holloway
Sam Holloway

Reputation: 121

Do you want the scrollStart() function to only fire once, the very first time a user scrolls? If do, this could be easily accomplished with a scrollStarted variable. if (scrollStarted == false) { scrollStarted = true; scrollStart(); }.

I can imagine a similar scenario if you want the function to fire when a user starts scrolling from the top (it can fire again if the user returns to the top). Just replace (scrollStarted == false) with scrollTop == 0.

Upvotes: 0

Related Questions