简体   繁体   English

使用useState钩子无法限制功能

[英]Can't throttle function with useState hook

I'm trying to throttle an event "wheel" on scroll using a lodash library for my React app with no success. 我正在尝试使用lodash库为我的React应用程序限制滚动事件“滚轮”但没有成功。

I need to listen to e.deltaY from scroll input in order to detect its scroll direction. 我需要从滚动输入中收听e.deltaY以检测其滚动方向。 To add a listener I wrote a React hook that accepts an event name and a handler function. 为了添加一个监听器,我编写了一个接受事件名称和处理函数的React钩子。

Base implementation 基础实施

  const [count, setCount] = useState(0);

  const handleSections = () => {
    setCount(count + 1);
  };

  const handleWheel = _.throttle(e => {
    handleSections();
  }, 10000);

  useEventListener("wheel", handleWheel);

My useEventListener hook 我的useEventListener钩子

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 工作演示: 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). 我的目标是限制这个滚动事件,以便减少事件触发并有几秒钟以编程方式滚动我的页面( scrollBy() ,例如)。 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. 当您可以在函数上调用_.throttle()时,您将获得一个“管理”原始函数调用的新函数。 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. 如果_.throttle()调用_.throttle() ,它将返回一个没有调用该函数的“历史”的新函数。 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 ): 使用useCallbacksandbox )将调用包装到_.throttle() ):

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM