Debounce в React es6 - PullRequest
       57

Debounce в React es6

1 голос
/ 12 июля 2020

У меня есть ввод для поиска на одной из моих страниц, и я пытаюсь убедиться, что он не делает 10 запросов за одну секунду, если пользователь набирает слишком быстро.

Похоже, что устранение неполадок - это способ на go. Я прочитал несколько сообщений в блогах и ТАК вопросы. Пытаюсь использовать debounce от loda sh. Я, должно быть, делаю что-то не так, потому что все мои вызовы передаются чуть позже.

Вот мой код компонента:

const Partners = (props: any) => {
  const [query, setQuery] = useState("");
  const { partners, totalPages, currentPage } = props.partnersList;

  useEffect(() => {
    props.getPartners();
  }, []);

  useEffect(() => debounce(() => props.getPartners(query), 10000), [query]);

  const handleQueryChange = (e: any) => {
    setQuery(e.target.value);
  };

  const handlePageChange = (e: React.ChangeEvent<unknown>, value: number) => {
    props.getPartners(query, value);
  };

  return (
    <React.Fragment>
      <Sidebar />
      <MainContent className="iamSearchPartners">
        <h1>Partners</h1>
        <TextField
          className="iamSearchPartners__search_input"
          variant="outlined"
          size="small"
          onChange={handleQueryChange}
          value={query}
        />
        <PartnersList partners={partners} />
        {totalPages > 1 && (
          <Pagination
            currentPage={currentPage || 1}
            totalPages={totalPages}
            handlePageChange={handlePageChange}
          />
        )}{" "}
      </MainContent>
    </React.Fragment>
  );
};

Как видите, у меня есть useEffect прослушивание изменений в запросе.

Ответы [ 2 ]

1 голос
/ 12 июля 2020

debounce создает противодействующую версию функции, переданной в качестве аргумента. В этом конкретном случае c вызов его в useEffect создаст новую версию функции с противодействием при каждом рендеринге. он не воссоздается при каждом рендеринге.

const myDebouncedFunction = debounce((handler, query) => handler(query), 10000);

const Partners = (props: any) => {
  // omitted ...
  useEffect(() => {
    myDebouncedFunction(props.getPartners, query);
  }, [query]);
  // omitted ...

useMemo или помещение его в useState тоже может сработать.

Еще одна вещь: useEffect вызывает только возвращенный debounced version, поскольку это стрелочная функция без фигурных скобок, поэтому она возвращает результат оценки. useEffect использует return своей функции как своего рода обработчик «отписки», см. Документацию React о «Эффектах с очисткой» . Таким образом, всякий раз, когда query изменялся (после второго раза), эффект вызывал функцию. Вышеупомянутая версия должна вызываться при каждом изменении запроса.

Лично я бы попытался обработать вызов версии функции с дебаундом в handleQueryChange вместо useEffect, чтобы сделать «когда должно ли это случиться "более ясно.

1 голос
/ 12 июля 2020

Честно говоря, я делаю это вручную. Обратите внимание на различия между debouncing и дросселированием . Я думаю, вы хотите ограничить количество запросов. Если вы откажетесь, ничего не произойдет, пока не закончится таймер.

Если вы хотите подождать 10 секунд, как в вашем примере, ничего не должно произойти, если пользователь вводит хотя бы один раз каждые десять секунд, до 10 секунд после последний тип. В отличие от дросселирования, при котором запрос будет go отправляться каждые 10 секунд.

Этот подход является своего рода гибридом, потому что мы следим за тем, чтобы последний из них все еще выходил (как это было бы при устранении неполадок), а дросселирование может нет, но мы по-прежнему отправляем запросы, пока пользователь печатает.

  const timer = useRef<number>(0);
  const lastEventSent = useRef(Date.now());

  useEffect(() => {
     if (Date.now() - lastEventSent.current < 500) {

     // The event was fired too recently, but we still want
     // to fire this event after the timeout if it is the last
     // one (500ms in this case).
      timer.current = setTimeout(() => {
          lastEventSent.current = Date.now();
          props.getPartners(query)
      }, 500);

     } else {

       // An event hasn't been fired for 500ms, lets fire the event
       props.getPartners(query)
       lastEventSent.current = Date.now();

       // And if the user was typing, there is probably a timer, lets clear that
       clearTimeout(timer.current);
     }
  
     // Cleanup the timer if there was one and this effect is reloaded.
     return () => clearTimeout(timer.current);

   }, [query]);
...