Anti-shake — это часто используемая инструментальная функция во фронтенд-бизнесе, а также часто встречающаяся проблема во фронтенд-интервью. Обычно при собеседовании с кандидатами каждый может использовать антишейк почерка, но с небольшой модификацией маленький партнер попадет в яму и погибнет. В этой статье описывается, как реализовать debounce в реагирующих хуках.
задний план
Debounce — это инструментальная функция, которая часто используется во внешнем интерфейсе, и это также вопрос, который я должен задать на собеседовании. После продвижения хуков React внутри команды я также добавил сопутствующие вопросы в интервью. как реализоватьuseDebounce
Это кажется очень простой проблемой, но на практике многие мелкие партнеры, которые запоминают код, просачиваются.
Проблемы, как правило, располагаются следующим образом:
- Что такое антишейк, троттлинг, объясните отдельно?
- Напишите вручную на белой бумаге функцию защиты от тряски или дросселирования, выберите свою (ограниченное время 4 минуты)
- Вы понимаете хуки реакции? Реализовать useDebounce, useThrottle на компьютере
- Там машинопись знаю?тс вернись с пиши еще раз
- ...
Постоянно переключая точки проверки вокруг темы, этот раунд проходит легко и плавно, и в то же время можно изучить много информации.
Фактическая ситуация такова, что многие кандидаты застревают на вопросе 3, о чем я должен сказать.
Восстановление сцены
Напишите антивибрационную функцию
Классическая функция устранения дребезга может выглядеть так:
function debounce(fn, ms) {
let timer;
return function(...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn(...args)
timer = null;
}, ms);
}
}
Изменить, чтобы реагировать хуки
Обеспечить тестовые случаи:
export default function() {
const [counter, setCounter] = useState(0);
const handleClick = useDebounce(function() {
setCounter(counter + 1)
}, 1000)
return <div style={{ padding: 30 }}>
<Button
onClick={handleClick}
>click</Button>
<div>{counter}</div>
</div>
}
Многие мелкие партнеры примут это как должное и изменят на это:
function useDebounce(fn, time) {
return debounce(fn, time);
}
Просто и элегантно, а код только что переиспользовал, тестирую, вроде проблем нет:
1-7292504.gif
Но если этот код будет помещен в производственную среду, вы будете забиты пользователем насмерть.
В самом деле?
Попробуйте другой вариант использования:
export default function() {
const [counter1, setCounter1] = useState(0);
const [counter2, setCounter2] = useState(0);
const handleClick = useDebounce(function() {
console.count('click1')
setCounter1(counter1 + 1)
}, 500)
useEffect(function() {
const t = setInterval(() => {
setCounter2(x => x + 1)
}, 500);
return clearInterval.bind(undefined, t)
}, [])
return <div style={{ padding: 30 }}>
<Button
onClick={function() {
handleClick()
}}
>click</Button>
<div>{counter1}</div>
<div>{counter2}</div>
</div>
}
2-7292504.gif
Проблема началась, когда был введен счетчик автонакопления2. В это время многие кандидаты начинают путаться, а некоторые кандидаты попытаются проанализировать причины. Только глубоко поняв принцип работы реактивных хуков во время повторного рендеринга, мы можем быстро найти проблему (на самом деле, не имеет значения, есть ли ошибка, маленький партнер, который может быстро найти проблему, — это то, что мы ищем) ).
Некоторые кандидаты случайно включили отладку Дафа, спешно модифицировав setCounter1:
const handleClick = useDebounce(function() {
console.count('click1')
setCounter1(x => x + 1)
}, 500)
Конечно, результаты все равно неверны, да и с характеристиками React Hooks не знаком...
Некоторые кандидаты догадывались, что это проблема с кешем повторного рендеринга, поэтому писали так:
function useDebounce(fn, delay) {
return useCallback(debounce(fn, delay), [])
}
в сотрудничествеsetCounter1(x => x + 1)
Правильные результаты можно получить с помощью модификации. Но это не решило проблему должным образом. Все еще неправильно. Заинтересованные читатели могут воспроизвести это явление, подумать, почему, и оставить сообщение для обсуждения.
в чем проблема?
Добавляем лог для использованияDebounce
function useDebounce(fn, time) {
console.log('usedebounce')
return debounce(fn, time);
}
3-7292504.gif
Консоль начинает выводить лог как сумасшедшая. Увидев это, многие читатели поймут. Если это немного более эффективный кандидат ранее, я могу дать чаевые здесь.
При каждом повторном рендеринге компонента все хуки будут выполняться один раз, поэтому таймер в функции высшего порядка debounce не может играть роль кэширования (каждый рендеринг пустой). Таймер ненадежен, а ядро debounce сломано.
Как настроить?
Есть много способов решить эту проблему. Например, используя механизм кэширования компонентов React:
function useDebounce(fn, delay, dep = []) {
const { current } = useRef({ fn, timer: null });
useEffect(function () {
current.fn = fn;
}, [fn]);
return useCallback(function f(...args) {
if (current.timer) {
clearTimeout(current.timer);
}
current.timer = setTimeout(() => {
current.fn.call(this, ...args);
}, delay);
}, dep)
}
Надежное использованиеDebounce может быть реализовано.
Аналогично напрямую приводим код useThrottle:
function useThrottle(fn, delay, dep = []) {
const { current } = useRef({ fn, timer: null });
useEffect(function () {
current.fn = fn;
}, [fn]);
return useCallback(function f(...args) {
if (!current.timer) {
current.timer = setTimeout(() => {
delete current.timer;
}, delay);
current.fn.call(this, ...args);
}
}, dep);
}
наконец
Использование реагирующих хуков может помочь нам установить некоторую общую логику состояния. При этом на ранней стадии внедрения реактивных хуков в продакшн-проекты следует уделять особое внимание скрытым опасностям, вызванным различиями в написании и принципах. В противном случае вы потеряете Цзинчжоу так же небрежно, как и кандидаты выше...
Давайте проанализируем причины, по которым в этом вопросе легко ошибиться:
- Небрежный. Дебаунс очень простой, а реагировать на хуки несложно, я никогда не думал, что при объединении будут ямки.
- Ментальный срыв. В сцене интервью, если вы столкнетесь с проблемой, которую раньше не видели, вы не сможете спокойно ее проанализировать.
- У меня нет глубокого понимания хуков реакции, и у меня не так много подводных камней.
- Я недостаточно знаком с debounce, и меня подозревают в запоминании кода.
Так как слишком много людей висит на этом вопросе, я решил поделиться им в надежде, что это может помочь всем.