why i get different value width window using react js? - javascript

example:
resize using react js
this is my code:
import React, { useState, useEffect } from 'react';
const getWidthWindow = () => {
const [widthWindow, setWidthWindow] = useState(null)
const updateDimensions = () => {
setWidthWindow(window.screen.width)
}
useEffect(() => {
console.log(widthWindow)
setWidthWindow(window.screen.width)
updateDimensions()
window.addEventListener('resize', updateDimensions)
return () => window.removeEventListener('resize', updateDimensions)
}, [widthWindow])
}
export default getWidthWindow;
I want to get the window width value but the result is like it doesn't match the window size so how to fix it?

Your code is correct but the logging isn't.
Add a hook to log the dimensions when it updates:
useEffect(() => {
console.log(windowDimensions)
}, [windowDimensions])
Working codesandbox.

I go with the above answer of adding windowDimensions to the useEffect's Dependency array but I like to add up little sugar on top of it..
On Resize, the event gets triggered continuously and impacts performance a bit..
So, I have implemented throttling to improve the performance..
Answer for your updated question: Stackblitz link
const GetWidthWindow = () => {
const [widthWindow, setWidthWindow] = useState(window.innerWidth);
useEffect(() => {
let throttleResizeTimer = null;
function handleResize() {
clearTimeout(throttleResizeTimer);
throttleResizeTimer = setTimeout(
() => setWidthWindow(window.innerWidth),
500
);
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, [widthWindow]);
return <p>{JSON.stringify(widthWindow)}</p>;
};
export default GetWidthWindow;
Answer for your old question:
useEffect(() => {
// implement throttle for little performance gain
let throttleResizeTimer = null;
function handleResize() {
clearTimeout(throttleResizeTimer);
throttleResizeTimer = setTimeout(
() => setWindowDimensions(getWindowDimensions()),
500
);
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize); }, [windowDimensions]);

Related

RemoveEventListener doesn't work inside useEffect

I try to make lazy loading for my products list using React and Redux. The problem is that I can't removeEventListener after all products are loaded.
all_loaded tells me if are products are loaded (true) or not (false).
So after the all_loaded changed to true, useEffect run code inside else but eventListener still exist after that.
const { all_loaded } = useAppSelector((state) => state.productsSlice);
const bottomScrollDetection = () => {
const position = window.scrollY;
var limit = document.body.offsetHeight - window.innerHeight;
if (position === limit) {
dispatch(fetchProducts(true));
}
};
useEffect(() => {
dispatch(fetchProducts(false));
if (!all_loaded) {
document.addEventListener("scroll", bottomScrollDetection);
} else {
document.removeEventListener("scroll", bottomScrollDetection);
}
}, [all_loaded]);
On the next re-render, a new function will be affected to bottomScrollDetection, the removeEventListener call will not remove the initial listener.
You can use the cleanup function :
useEffect(() => {
if (!all_loaded) {
dispatch(fetchProducts(false));
document.addEventListener("scroll", bottomScrollDetection);
return () => document.removeEventListener("scroll", bottomScrollDetection);
}
}, [all_loaded]);

If I refresh the page matchMedia doesn't work

I'm using matchMedia in React to collapse my SideBar when the page is resizing. But the problem is if I refresh the page, my sidebar is open not closed. So if I want to collapse my SideBar I need to resize the page again or use the close button.
const layout = document.getElementById('home-layout');
const query = window.matchMedia('(max-width: 765px)');
query.onchange = (evt) => {
if( query.matches ) {
changeMenuMinified(true);
layout.classList.add('extended-layout');
}
else {
changeMenuMinified(false);
layout.classList.remove('extended-layout');
}
};
query.onchange();
};
useEffect(() => {
window.addEventListener('resize', handleResize);
});
If I remove addEventListener it works, I can reload the page and my sidebar stays closed but if I try to open the sidebar with a button, the sidebar closes quickly
const handleResize = () => {
const layout = document.getElementById('home-layout');
const query = window.matchMedia('(max-width: 765px)');
query.onchange = (evt) => {
if( query.matches ) {
changeMenuMinified(true);
layout.classList.add('extended-layout');
}
else {
changeMenuMinified(false);
layout.classList.remove('extended-layout');
}
};
query.onchange();
};
useEffect(() => {
handleResize()
});
sideBar
Some stuff to consider here:
Initialize your state with the current matching value
Remove listener on effect cleanup function
Don't forget the useEffect dependency array to avoid your code being executed on each render.
You can find a working example here -> https://codesandbox.io/s/stack-72619755-lpwh6m?file=/src/index.js:0-613
const query = window.matchMedia('(max-width: 765px)')
const App = () => {
const [minified, changeMenuMinified] = useState(query.matches)
useEffect(() => {
const resizeHandler = () => {
if (query.matches) {
changeMenuMinified(true)
} else {
changeMenuMinified(false)
}
}
query.addEventListener("change", resizeHandler);
return () => query.removeEventListener("change", resizeHandler);
})
return <p>{minified ? 'minified' : 'expanded'}</p>
}
That's because you need to have both in order to work, on load and also on reside, for that you can just do so:
Notice I added that empty dependencies array.
useEffect(() => {
handleResize();
window.addEventListener('resize', handleResize);
},[]);

Canceling a timeout in useEffect() if user scrolls with react hooks

Basically the same question as How to cancel a javascript function if the user scrolls the page but using react hooks.
I wrote react code that scrolls down to the end of the page after 3 seconds.
const scrollToEnd = () => { /* implementation omitted */ }
useEffect(() => {
const id = setTimeout(() => scrollToEnd(), 3000)
return () => clearTimeout(id)
}, [])
I want modify this code so that if the user manually scrolls the page before this timeout, the timeout is cleared.
I was thinking of a solution like:
const [hasScrolled, setHasScrolled] = useState(false);
const scrollToEnd = () => { /* implementation omitted */ }
useEffect(() => {
const setHasScrolledCallback = () => setHasScrolled(true)
window.addEventListener("scroll", setHasScrolledCallback);
return () => window.removeEventListener("scroll", setHasScrolledCallback);
}, []);
useEffect(() => {
const scrollCallback = () => { if (hasScrolled) scrollToEnd() }
const id = setTimeout(scrollCallback, 3000)
return () => clearTimeout(id)
}, [])
This works, but I don't think this is the correct way to approach this problem, because the scroll event is fired multiple times, even after the timeout occurs. Also the scrollCallback isn't really canceled, it runs anyway even if it does nothing.

Callback not firing on resize within React Hook

I get the console log to fire inside the hook on each resize however the console log that's in the callback that gets passed into the resize hook never fires.
Here is the hook i have which uses useCallbacks per the exhaustive deps eslint plugin:
// #flow
import { useCallback, useEffect } from 'react';
let resizeId: AnimationFrameID;
export const useResize = (callbackFn: Function, ref?: any) => {
const resizeUpdate = useCallback(() => {
console.log('inside');
callbackFn();
}, [callbackFn]);
const handleResize = useCallback(() => {
cancelAnimationFrame(resizeId);
resizeId = requestAnimationFrame(resizeUpdate);
}, [resizeUpdate]);
const handleOrientation = useCallback(() => {
// After orientationchange, add a one-time resize event
const afterOrientationChange = () => {
handleResize();
// Remove the resize event listener after it has executed
window.removeEventListener('resize', afterOrientationChange);
};
window.addEventListener('resize', afterOrientationChange);
}, [handleResize]);
useEffect(() => {
if (typeof ResizeObserver === 'function' && ref && ref.current) {
let resizeObserver = new ResizeObserver(() => handleResize());
resizeObserver.observe(ref.current);
return () => {
if (!resizeObserver) {
return;
}
resizeObserver.disconnect();
resizeObserver = null;
};
} else {
window.addEventListener('resize', handleResize);
window.addEventListener('orientationchange', handleOrientation);
return () => {
window.removeEventListener('resize', handleResize);
window.removeEventListener('orientationchange', handleOrientation);
cancelAnimationFrame(resizeId);
};
}
}, [callbackFn, handleOrientation, handleResize, ref]);
};
export default useResize;
Here is how you use it within a component:
...
const setContentRef = () => {
console.log('resize');
};
useResize(setContentRef);
...

addEventListener does not work within a useEffect hook

The following is a component whose functionality, partly, is to change the window's title as the page is getting focused and blurred. It does not work.
const ATitleChangingComponent = () => {
const focusFunction = (event: FocusEvent) => {
document.title = "focused";
};
const blurFunction = (event: FocusEvent) => {
document.title = "blurred";
};
useEffect(() => {
window.addEventListener("focus", focusFunction);
return window.removeEventListener("focus", focusFunction);
}, []);
useEffect(() => {
window.addEventListener("blur", blurFunction);
return window.removeEventListener("blur", blurFunction);
}, []);
return <p>some unimportant jsx</p>
};
However,
const focusFunction = (event: FocusEvent) => {
document.title = "focused";
};
window.addEventListener("focus", focusFunction);
works just fine.
A side question: are const focusFunction and const blurFunction getting constructed within the function each render? I assume if so, they should be lifted out of the component to avoid unnecessary overhead?
Need to return a function, otherwise listener is removed immediately.
The function gets called when the component unmounts
useEffect(() => {
window.addEventListener("blur", blurFunction);
return () => window.removeEventListener("blur", blurFunction);
}, []);

Categories