Ответ вслух Junior Код-ревью спрашивают часто обновлено

Ревью: debounce в компоненте

Вопрос

Перед тобой код на ревью. Скажи вслух, что здесь не так - по убыванию важности.

Читай вслух, как на ревью: сначала что делает код, потом что сломано.

function Search() {
  const [value, setValue] = useState('');

  const search = debounce((q) => {
    fetch('/api/search?q=' + q).then(/* ... */);
  }, 300);

  return <input value={value} onChange={(e) => { setValue(e.target.value); search(e.target.value); }} />;
}

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Главная ошибка - debounce вызывается в теле компонента. Каждый ввод символа вызывает рендер, рендер создаёт новую отложенную функцию с новым таймером, и старый таймер никого не отменяет.

Что должно прозвучать в ответе

  • debounce создаётся заново на каждом рендере - откладывание не работает

  • нужен useMemo или useRef, чтобы функция пережила рендер

  • нет отмены отложенного вызова при размонтировании

  • q не экранирован через encodeURIComponent

  • нет отмены предыдущего запроса - остаётся гонка

  • проще перенести задержку в эффект с зависимостью от value

Что могут спросить следом

  • Почему вариант с useEffect чище?
  • Debounce убирает гонку запросов полностью?

Разбор

Главная ошибка - debounce вызывается в теле компонента. Каждый ввод символа вызывает рендер, рендер создаёт новую отложенную функцию с новым таймером, и старый таймер никого не отменяет. В результате запрос уходит на каждое нажатие с задержкой 300 мс - то есть debounce не работает вообще, хотя код выглядит правильным.

Лечение: useMemo(() => debounce(fn, 300), []) или useRef. Но чище убрать библиотеку и сделать эффектом:

useEffect(() => {
  const id = setTimeout(() => load(value), 300);
  return () => clearTimeout(id);
}, [value]);

Здесь очистка сама отменяет предыдущий таймер, и размонтирование обработано.

Остаются два пункта: encodeURIComponent для запроса и отмена самого запроса - задержка уменьшает число гонок, но не устраняет их.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.