Не могу регулировать функцию с помощью крючка useState - PullRequest
3 голосов
/ 21 июня 2019

Я пытаюсь задушить "колесо" события при прокрутке, используя библиотеку lodash для моего приложения React, но безуспешно.

Мне нужно прослушать e.deltaY со входа прокрутки, чтобы определить направление его прокрутки. Чтобы добавить слушателя, я написал хук React, который принимает имя события и функцию-обработчик.

Базовая реализация

  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);
    };
  });
}

Рабочая демоверсия: https://codesandbox.io/s/throttledemo-hkf7n

Моя цель состоит в том, чтобы задушить это событие прокрутки, чтобы было меньше событий и иметь несколько секунд для прокрутки моей страницы программно (scrollBy(), пример). В этот момент кажется, что регулирование не работает, поэтому я получаю много событий прокрутки одновременно

1 Ответ

5 голосов
/ 21 июня 2019

Когда вы можете вызвать _.throttle() для функции, вы получите новую функцию, которая «управляет» вызовом исходной функции. Всякий раз, когда вызывается функция-обертка, обертка проверяет, прошло ли достаточно времени, и если это так, то вызывает исходную функцию.

Если _.throttle() вызывается несколько раз, возвращается новая функция, у которой нет «истории» вызова функции. Затем он будет снова и снова вызывать исходную функцию.

В вашем случае упакованная функция восстанавливается при каждом рендере. Завершение вызова на _.throttle() с useCallback ( песочница ):

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>
...