I'm trying to throttle an event "wheel" on scroll using a lodash library for my React app with no success.
I need to listen to e.deltaY from scroll input in order to detect its scroll direction. To add a listener I wrote a React hook that accepts an event name and a handler function.
Base implementation
const [count, setCount] = useState(0);
const handleSections = () => {
setCount(count + 1);
};
const handleWheel = _.throttle(e => {
handleSections();
}, 10000);
useEventListener("wheel", handleWheel);
My useEventListener hook
function useEventListener(e, handler, passive = false) {
useEffect(() => {
window.addEventListener(e, handler, passive);
return function remove() {
window.removeEventListener(e, handler);
};
});
}
Working demo: https://codesandbox.io/s/throttledemo-hkf7n
My goal is to throttle this scroll event in order to have less events firing and to have a few seconds to scroll my page programmatically (scrollBy(), par example).
At this moment throttling seem to not work so I'm getting lots of scroll events all at once
When you can call _.throttle() on a function, you get back a new function that "manages" the invocation of the original function. Whenever the wrapper function is called, the wrapper checks if enough time passed, and if so it calls the original function.
If _.throttle() is called multiple times, it returns a new function that doesn't have the "history" of calling the function. It will then call the original function again and again.
In your case the wrapped function is regenerated on each render. Wrap the call to _.throttle() with useCallback (sandbox):
const { useState, useCallback, useEffect } = React;
function useEventListener(e, handler, cleanup, passive = false) {
useEffect(() => {
window.addEventListener(e, handler, passive);
return function remove() {
cleanup && cleanup(); // optional specific cleanup for the handler
window.removeEventListener(e, handler);
};
}, [e, handler, passive]);
}
const App = () => {
const [count, setCount] = useState(0);
const handleWheel = useCallback(_.throttle(() => {
setCount(count => count + 1);
}, 10000, { leading: false }), [setCount]);
useEventListener("wheel", handleWheel, handleWheel.cancel); // add cleanup to cancel throttled calls
return (
<div className="App">
<h1>Event fired {count} times</h1>
<h2>It should add +1 to cout once per 10 seconds, doesn't it?</h2>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.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 id="root"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With