Я нашел этот код из этого ответа 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 раза?
Я что-то неправильно понимаю?
Я не понимаю код
Вы не понимаете, что делает дебаунсинг. Функция устранения дребезга не вызывается до тех пор, пока она не будет запущена в течение периода задержки. Другими словами, если вы продолжаете вводить буквы в течение задержки, обратный вызов продолжает отклоняться. Когда вы перестанете печатать, то по истечении задержки вы получите один звонок.
@DrewReese Это не так, я знаю, как должно работать осуждение. Однако я не был уверен, почему приведенный выше код работает, поскольку думал, что компоненты размонтируются только после их уничтожения. Не знал, что он также отключится при изменении данных.
Компоненты «уничтожаются» (если вы это так называете) при размонтировании. Они, конечно, не размонтируются при обновлении состояний, а просто перерисовываются. Вы хотели сказать, что не поняли, что функция очистки перехвата useEffect
запускается до применения следующего эффекта и при размонтировании компонента?
Но когда я проверил
console.info()
, выполнил только один раз, почему бы и нетsetTimeout()
выполнить 3 раза?
Потому что каждый раз, когда меняется одна из ваших зависимостей (например: searchQuery
или delay
), сначала запускается функция очистки, очищающая предыдущий запланированный тайм-аут, а затем она запускает обратный вызов useEffect, чтобы запланировать новый тайм-аут.
Итак, поведение, которое вам не хватает, заключается в том, что предыдущий тайм-аут очищается, когда пользователь вводит "abc"
:
searchQuery
будет "a"
, очистите предыдущий тайм-аут (если он существует, технически он будет запланирован при подключении) и запланируйте новый setTimeout()
для запуска через 5 секунд.searchQuery
будет "ab"
, очистите предыдущий тайм-аут (чтобы никогда не выполнять обратный вызов сейчас) и запланируйте запуск нового setTimeout()
через 5 секунд.searchQuery
будет "abc"
, очистите предыдущий тайм-аут (чтобы никогда не выполнять обратный вызов сейчас) и запланируйте запуск нового setTimeout()
через 5 секунд.Тайм-аут завершается, поскольку ничего не очищается, и вы видите журнал setTimeout called
.
Насколько я понимаю, компоненты размонтируются только тогда, когда компонент уничтожается. Я не знал, что обновления данных также отключили его. Можете ли вы указать мне на правильные документы, чтобы лучше понять это поведение?
@Baxu См. act.dev/reference/react/useEffect
@Baxu Это не размонтирование, просто функция очистки (которая также вызывается при размонтировании) также вызывается, когда ваши зависимости изменяются (более подробную информацию см. по ссылке Дрю, в частности, о параметре setup).
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;
}
Разделив состояние входного элемента и значение устранения дребезга, вы получаете доступ к обоим:
Из-за
() => clearTimeout(delayFn);
, который вызывается всякий раз, когда useeffect повторно запускается из-за изменений зависимостей. Это очищает ожидающий тайм-аут и создает новый.