Работа пользовательского крючка реагирования useSearchDebounce

Я нашел этот код из этого ответа https://stackoverflow.com/a/68780417/26420821

Как это работает?

export function useSearchDebounce(delay = 350) {
  const [search, setSearch] = useState(null);
  const [searchQuery, setSearchQuery] = useState(null);

  useEffect(() => {
    const delayFn = setTimeout(() => {
        console.info("setTimeout called");
        setSearch(searchQuery);
    }, delay);

    return () => clearTimeout(delayFn);
  }, [searchQuery, delay]);

  return [search, setSearchQuery];
}

Использование :

const [search, setSearch] = useSearchDebounce();

<input onChange = {(e) => setSearch(e.target.value)}/>

Если предположить, что пользователь вводит «abc» вместе в поле ввода с задержкой, установленной на 5000,

Сначала searchQuery будет "a" , он setTimeout() запустится через 5 секунд,

Затем searchQuery будет "ab" , он снова setTimeout() побежит через 5 секунд,

Затем searchQuery будет "abc" , снова setTimeout() бежать через 5 секунд

Но когда я проверил console.info(), выполнил только один раз, почему setTimeout() не выполнил 3 раза?

Я что-то неправильно понимаю?

Я не понимаю код

Из-за () => clearTimeout(delayFn);, который вызывается всякий раз, когда useeffect повторно запускается из-за изменений зависимостей. Это очищает ожидающий тайм-аут и создает новый.

Gabriele Petrioli 18.07.2024 17:04

Вы не понимаете, что делает дебаунсинг. Функция устранения дребезга не вызывается до тех пор, пока она не будет запущена в течение периода задержки. Другими словами, если вы продолжаете вводить буквы в течение задержки, обратный вызов продолжает отклоняться. Когда вы перестанете печатать, то по истечении задержки вы получите один звонок.

Drew Reese 21.07.2024 23:32

@DrewReese Это не так, я знаю, как должно работать осуждение. Однако я не был уверен, почему приведенный выше код работает, поскольку думал, что компоненты размонтируются только после их уничтожения. Не знал, что он также отключится при изменении данных.

Baxu 23.07.2024 07:38

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

Drew Reese 23.07.2024 07:47
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
57
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Но когда я проверил console.info(), выполнил только один раз, почему бы и нет setTimeout() выполнить 3 раза?

Потому что каждый раз, когда меняется одна из ваших зависимостей (например: searchQuery или delay), сначала запускается функция очистки, очищающая предыдущий запланированный тайм-аут, а затем она запускает обратный вызов useEffect, чтобы запланировать новый тайм-аут.

Итак, поведение, которое вам не хватает, заключается в том, что предыдущий тайм-аут очищается, когда пользователь вводит "abc":

  • searchQuery будет "a" , очистите предыдущий тайм-аут (если он существует, технически он будет запланирован при подключении) и запланируйте новый setTimeout() для запуска через 5 секунд.
  • searchQuery будет "ab" , очистите предыдущий тайм-аут (чтобы никогда не выполнять обратный вызов сейчас) и запланируйте запуск нового setTimeout() через 5 секунд.
  • searchQuery будет "abc" , очистите предыдущий тайм-аут (чтобы никогда не выполнять обратный вызов сейчас) и запланируйте запуск нового setTimeout() через 5 секунд.

Тайм-аут завершается, поскольку ничего не очищается, и вы видите журнал setTimeout called.

Насколько я понимаю, компоненты размонтируются только тогда, когда компонент уничтожается. Я не знал, что обновления данных также отключили его. Можете ли вы указать мне на правильные документы, чтобы лучше понять это поведение?

Baxu 23.07.2024 07:35

@Baxu См. act.dev/reference/react/useEffect

Drew Reese 23.07.2024 07:50

@Baxu Это не размонтирование, просто функция очистки (которая также вызывается при размонтировании) также вызывается, когда ваши зависимости изменяются (более подробную информацию см. по ссылке Дрю, в частности, о параметре setup).

Nick Parsons 23.07.2024 09:18

export function Filter() {
  const [filter, setFilter] = useState("");
  const debounced = useDebounce(filter);

  return (
    <>
      <input value = {filter} onChange = {(e) => setFilter(e.target.value)} />
      <div>{`Debounced Value: ${debounced}`}</div>
    </>
  );
}

function useDebounce<T>(value: T, delay = 300) {
  const [debounced, setDebounced] = useState<T>(value);

  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setDebounced(value);
    }, delay);

    return () => {
      clearTimeout(timeoutId);
    };
  }, [delay, value]);

  return debounced;
}

Разделив состояние входного элемента и значение устранения дребезга, вы получаете доступ к обоим:

  • немедленное обновление входного элемента
  • отложенное обновление значения устранения дребезга (в примере элемент div)

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