Search code examples
javascriptreactjsthrottling

How to throttle onWheel events in a React functional component


I have this Reactemphasized text component that I want to do something when a wheel event occurs. But I also want to throttle the wheel events and make sure only one event will trigger the function for two seconds. I am using the throttle function from lodash library.

However, it still fires lots of events and all of them will be executed. I think the cause is that every wheel event produces a unique throttled function. But I have no idea how to make solve the issue and make it work as expected. Could anyone provide me any possible solutions?

Any comments would be appreciated.

  const changePage = (direction) => {
    if (direction > 0) {
      console.log("scroll down");
    } else {
      console.log("scroll up");
    }
  };
  const onWheel = (event) => {
    changePage(event.deltaY);
  };
    
  <div className="name" onWheel={_.throttle(onWheel, 2000)} >

Solution

  • You can use useMemo with an empty dependency array so that the _.throttle is only called once, on mount:

    const changePage = (direction) => {
      if (direction > 0) {
        console.log("scroll down");
      } else {
        console.log("scroll up");
      }
    };
    const onWheel = (event) => {
      changePage(event.deltaY);
    };
    const onWheelThrottled = useMemo(() => _.throttle(onWheel, 2000), []);
    
    <div className="name" onWheel={onWheelThrottled} >
    

    Live snippet:

    console.error = () => void 0;
    const App = () => {
      const changePage = (direction) => {
        if (direction > 0) {
          console.log("scroll down");
        } else {
          console.log("scroll up");
        }
      };
      const onWheel = (event) => {
        changePage(event.deltaY);
      };
      const onWheelThrottled = React.useMemo(() => _.throttle(onWheel, 2000), []);
      return <div className="name" onWheel={onWheelThrottled} />
    };
    ReactDOM.render(<App />, document.querySelector('.react'));
    .name {
      height: 3000px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
    <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <div class="react"></div>