Есть ли способ отправить поисковый запрос в React, только когда кто-то перестает печатать?

Я использую React 16.13.0. У меня есть это поле поиска, где люди вводят и ожидают увидеть результаты по мере ввода...

return (
  <div className="searchForm">
    <input
      type="text"
      placeholder="Search"
      value={this.state.searchTerm}
      onChange={this.handleChange}
    />

Я использую следующие функции для обработки результатов, когда люди вводят...

  handleChange(event) {
    const query = event.target.value;
    if (!query) {
      this.setState({ searchTerm: query, searchResults: [] });
    } else {
      this.setState({ searchTerm: query, loading: true }, () => {
        this.doSearch(query);
      });
    }
  }

  doSearch = (query) => {
    const searchUrl = "/coops/?contains=" + encodeURIComponent(query);
    fetch(searchUrl, {
      method: "GET",
    })
      .then((response) => response.json())
      .then((data) => {
        if (query === this.state.searchTerm) {
          this.setState({
            searchResults: data,
            loading: false,
          });
        }
      });
  };

Я пытаюсь сократить количество выполняемых / обрабатываемых сетевых вызовов. Если кто-то довольно быстро набирает строку типа "res", его, вероятно, не волнуют результаты для "r" или "re", поэтому мне было интересно, есть ли способ отменить запрос, если новый письмо введено в мое поле поиска? Или выполнять поиск только в том случае, если кто-то перестал печатать как минимум на 100 мс (не уверен, достаточно ли этого времени, но решил выбрать произвольное количество)?

3 ответа

Решение

То, что вам нужно, обычно называют дребезгом. Существует ряд библиотек, реализующих эту функцию, в т.ч. lodash и подчеркивание. В lodash, например, вы должны сделать следующее:

      onChange={e => debouncedHandler(e, this.handleChange)}

и определил следующее вне компонента:

const debouncedHandler = _.debounced((e, handler) => handler(e), 100);

Распространенная ошибка - объявлять отклоняемую функцию внутри самого компонента. Это не сработает, потому что response повторяет этот код при каждом изменении и, следовательно, воссоздает функцию, для которой устранена ошибка, поэтому устранение ошибки не произойдет. Поэтому важно определить противодействующую функцию вне компонента.


Обновление: в коде, который у меня был ранее, была ошибка. Думаю, теперь это исправлено. Я не проверял это.

Вы можете использовать такой помощник и передать вызывающую функцию в качестве первого аргумента callback.

function getDoneTyping (callback, wait = 300) {
  let timer
  const keyDownHandler = event => {
    if (event.key === 'Enter') {
      callback()
    }
    clearTimeout(timer)
  }

  const keyUpHandler = event => {
    clearTimeout(timer)
    timer = setTimeout(callback, wait)
  }
  return { keyDownHandler, keyUpHandler }
}

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

handleChange = (e) => {
    this.setState(
        {
            searchTerm: e.target.value
        },
        () => {
            try {
                clearInterval(window.xhrSearchTimer);
            } catch (e) {
                console.log(`no timeout initialized`);
            }

            window.xhrSearchTimer = window.setTimeout(() => {
                this.doSearch(this.state.searchTerm);
            }, 1000); // arbitrary value
        }
    );
};

doSearch = () => {
    alert(`Now searching for ${this.state.searchTerm}`);
};

https://codesandbox.io/s/loving-sid-hb0nr?file=/src/App.js:139-622

Другие вопросы по тегам