Извините за длинный вопрос, но мне нужно было сделать введение, чтобы прояснить его.
Мне нужен был какой-то код для переключения между моими компонентами заголовков <HeaderDesktop>
и <MobileHeader>
.
Сначала я использовал медиазапросы CSS для переключения между ними с помощью display: block | none;
.Это менее чем идеально, так как оба компонента будут отображаться одновременно, что неэффективно и может привести к проблемам при отображении рекламы на скрытых элементах.
Кто-то здесь, на SO, предложил мне использовать window.innerWidth
ииспользуйте React, чтобы определить, какой компонент визуализировать на основе этого.Это действительно намного лучше.Теперь только один компонент отображается одновременно.Вот что я сделал:
// INSIDE HEADER COMPONENT
return(
<HeaderWrapper>
{window.innerWidth < 1200 ?
<HeaderMobile/>
: <HeaderDesktop/>
}
</HeaderWrapper>
);
Но мне нужен был способ обработки событий изменения размера.Так я и сделал:
// INSIDE HEADER COMPONENT
const [windowSize, setWindowSize] = useState(window.innerWidth);
function handleResize() {
setWindowSize(window.innerWidth);
}
return(
<HeaderWrapper>
{windowSize < 1200 ?
<HeaderMobile/>
: <HeaderDesktop/>
}
</HeaderWrapper>
);
Отлично!Это работает, но теперь мой компонент рендерит 1 триллион раз в секунду каждый раз, когда происходит изменение размера.Это плохо для производительности.
Итак, я провел исследование и выяснил методы lodash throttle
и debounce
.Оба могут уменьшить и контролировать количество обработанных событий, даже если сотни запускаются последовательно.
https://css -tricks.com / debouncing-throttling-объясн-examples /
Но я не фанат включения целых библиотек в свой список зависимостей только для того, чтобы использовать простую функциональность, подобную этой, поэтому я закончил тем, что создал следующий хук для эффекта, имитирующий функциональность throttle
для моего события resize
обработчик.
// INSIDE HEADER COMPONENT
// Ref to store if there's a resize in progress
const resizeInProgress = useRef(false);
// State to store window size
const [windowSize, setWindowSize] = useState(window.innerWidth);
useEffect(() => {
// This function trigger the resize event handler
// And updates the ref saying that there's a resize in progress
// If theres a resize in progress, it doesn't do anything
function handleResize() {
if (resizeInProgress.current === true) {
return;
}
resizeInProgress.current = true;
throttled_updateWindowSize();
}
// This function sets a timeout to update the state with the
// new window size and when it executes, it resets the
// resizeInProgress ref to false. You can execute what's the interval
// You want to handle your resize events, in this case is 1000ms
function throttled_updateWindowSize() {
setTimeout(() => {
console.log("I will be updated!");
console.log(window.innerWidth);
setWindowSize(window.innerWidth);
resizeInProgress.current = false;
}, 1000);
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
Вы можете увидеть это в действии в следующей песочнице:
https://codesandbox.io/s/v3o0nmvvl0
![enter image description here](https://i.stack.imgur.com/VQfwl.png)
ВОПРОС 1
Можете ли вы дать мне какие-либо предложения о том, как улучшить мой код для дросселированной версии обработчика событий изменения размера?
ВОПРОС 2
Я предполагаю, что мне понадобятся эти функции в других компонентах.Как я могу сделать это легко многоразовым?Могу ли я сделать этот кастомный крючок?Я никогда не создавал его, поэтому у меня все еще есть проблемы с тем, как рассуждать о них и как правильно их создавать.Можете ли вы помочь мне поместить это в Custom Hook?
Или лучше создать для этого компонент высшего порядка?