⚡️(responsive) add debounce to resize event listener - #262
Conversation
Ovgodd
left a comment
There was a problem hiding this comment.
Just a question regarding your debounce function
| const debouncedResizeHandler = () => { | ||
| setTimeout(() => { | ||
| handleResize(); | ||
| }, 300); | ||
| }; | ||
|
|
||
| window.addEventListener("resize", debouncedResizeHandler); |
There was a problem hiding this comment.
I think this is more a simple "delay" than a real debounce,
I a have a feeling that If the user keeps resizing for ~1s,
handleResize() will still run multiples times
a proper debounce should cancel the previouis timer before scheduling a new one WDYT ?
here is a proposal :
useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout>;
const RESIZE_DEBOUNCE_MS = 200
const handleResize = () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
// Update React when the window crosses a breakpoint (mobile/tablet/desktop)
// Without this, components would keep the values from the initial render
setResponsiveStates(getResponsiveStates(window.innerWidth, breakpoints));
}, RESIZE_DEBOUNCE_MS);
};
window.addEventListener("resize", handleResize);
return () => {
clearTimeout(timeoutId);
window.removeEventListener("resize", handleResize);
};
}, []);
There was a problem hiding this comment.
Yes you're totally right.
| const debouncedResizeHandler = () => { | ||
| setTimeout(() => { | ||
| handleResize(); | ||
| }, 300); | ||
| }; | ||
|
|
||
| window.addEventListener("resize", debouncedResizeHandler); |
There was a problem hiding this comment.
A clearTimeout is missing here. Currently, you just delay all event of 300ms.
Furthermore, here I'll use throttling not debounce.
There was a problem hiding this comment.
For efficiency I'll rewrite the effect without deps to prevent to add and remove listener each time responsiveStates changes.
useEffect(() => {
let timeoutId: ReturnType<typeof setTimeout> | undefined;
let pending: boolean = false;
const handleResize = () => {
const newResponsiveState = getResponsiveStates(window.innerWidth, breakpoints);
setResponsiveStates((oldResponsiveStates) => {
const isSame = (
Object.keys(oldResponsiveStates) as (keyof ResponsiveStates)[]
).every((key) => oldResponsiveStates[key] === newResponsiveState[key]);
return isSame ? oldResponsiveStates : newResponsiveState;
});
};
const throttledResizeHandler = () => {
if (pending === true) return;
pending = true;
timeoutId = setTimeout(() => {
pending = false;
handleResize();
}, 300);
};
window.addEventListener("resize", throttledResizeHandler);
// Cleanup on unmount
return () => {
clearTimeout(timeoutId);
window.removeEventListener("resize", throttledResizeHandler);
};
}, []);There was a problem hiding this comment.
Far better pattern, adopted ✅
Resize event listener is now debounced to improve performance and prevent excessive re-renders during window resizing. The debounce delay is set to 300 milliseconds.
ed960fc to
0ef4f29
Compare
Purpose
Resize event listener is now debounced to improve performance and prevent excessive re-renders during window resizing.
The debounce delay is set to 300 milliseconds.