React input debounce все еще выполняющийся метод

#javascript #reactjs #debounce

#javascript #reactjs #отмена

Вопрос:

Я пытаюсь реализовать debounce, но не могу заставить его работать (все еще слишком много запросов на каждое изменение ввода). Я использую debounce метод из underscore . Я упростил свой код для этого примера:

 import { debounce } from "underscore";

const fetch = (value) => {
    axios.post("/uri", { search: value }).then(({ data }) => {   
      setBreeds(data);
    });
  };

<input
  type="text"
  onChange={e => debounce(fetch(e.target.value), 2000)}
  autoComplete="off"
/>
  

Что я мог здесь делать не так?

Ответ №1:

Ваша основная проблема заключается в том, что для debounce требуется функция в качестве первого аргумента. Вы передаете fetch(e.target.value) в качестве первого аргумента, который даже не является функцией (это обещание). Но для того, чтобы оценить, что это за аргумент, fetch он должен вызываться каждый раз onChange , когда происходит событие — вот почему вы видите, что он вызывается слишком часто.

«Правильный» способ написать это вместо:

 onChange={debounce(e => fetch(e.target.value), 2000)}
  

Однако даже это не будет работать так, как задумано, просто потому, что onChange эта функция должна пересчитываться каждый раз при повторном запуске компонента, поэтому, хотя debounce внутренне будет отказываться вызывать свою базовую функцию, пока с момента последнего времени не пройдет 2 секунды, эта функция изменит идентичность между повторными запусками, даже если это будет «та же функция» насколько вас это касается. То, что две функции имеют одинаковые реализации и эффекты, не означает, что они являются одной и той же ссылкой на функцию.

Поэтому вместо этого вам нужно извлечь функцию e => fetch(e.target.value) , чтобы она имела единый идентификатор. Не сразу понятно, как это сделать в функциональном компоненте (в классе это просто, просто сделайте функцию методом экземпляра — я предполагаю, что это функциональный компонент, хотя из-за использования вызываемой функции setBreeds ), но это можно сделать с помощью useRef или useCallback — см., Например, Эту статью, кака также документацию для этих двух перехватов на сайте React.

Ответ №2:

Согласно https://underscorejs.org/#debounce , debounce() должна иметь функцию в качестве первого аргумента, тогда как (мне кажется) вы отправляете результат вызова функции. Возможно:

 onChange={e => debounce(fetch(e.target.value), 2000)}
  

Может быть изменен на:

 onChange={e => debounce(() => fetch(e.target.value), 2000)}
  

Ответ №3:

Попробуйте создать функцию debounceCall и использовать e.persist

  const debounceCall = debounce(e => {
    axios.post("/uri", { search: e.target.value }).then(({ data }) => {
       setBreeds(data);
    });
 }, 2000);

  <input
    type="text"
    name="inp"
    onChange={e => {
      e.persist();
      debounceCall(e);
    }}
    autoComplete="off"
  />