am trying to give a number according to the window width is react but is only setting te width according to the first IF statement, please could be wrong with my code.
Here's it
const hasWindow = typeof window !== 'undefined';
const [widthsize, setWidthsize] = useState<number>()
const width = hasWindow ? window.innerWidth : null;
useEffect(()=> {
if(width !== null && width < 500){
setWidthsize(300)
} else if(width !== null && width > 500){
setWidthsize(1000)
}else{
setWidthsize(100)
}
},[width])
CodePudding user response:
Add eventListener on resize
event:
const hasWindow = typeof window !== 'undefined';
const [widthsize, setWidthsize] = useState<number>()
const width = hasWindow ? window.innerWidth : null;
const handleResize = () => {
if(width !== null && width < 500){
setWidthsize(300)
} else if(width !== null && width > 500){
setWidthsize(1000)
}else{
setWidthsize(100)
}
}
useEffect(() => {
window.addEventListener("resize", handleResize);
handleResize();
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
CodePudding user response:
The window.innerWidth
won't update automatically on window resize as it seems that's what you want to happen. If you want it to update on window resize, you need to explicitly attach an event listener inside another useEffect with an empty array dependency so that the event is registered only once. Instead of using plain variable to store the window-innerWidth
value, you should use an state on which the second useEffect depends which then will have an access to the updated width depending on which you can set the widthSize
inside it. One more thing is you don't want the component to re-render on every resize event. That's why I have used setTimeout()
and clearTimeout()
functions to trigger the resize event only once after event starts and after a specified duration i.e. 500ms as in the below code. This is just a straight forward workaround. If you are using jquery, here is the perfect solution for that scenario. Used react useRef
for the timeOutId
to persists its value so that we know we are clearing the correct time out on next resize event before firing another one. We are using separate useEffect for event listener because if we merge it to the same useEffect, then we will be registering the event every time there is change in width
dependency which you wouldn't want it to happen unless you are removing the listener. Plus it's separation of concern and more cleaner. I am displaying widthSize
inside H1 tag below just so you know it is working.
import "./styles.css";
import {useEffect, useState, useRef} from 'react';
export default function App() {
const hasWindow = typeof window !== 'undefined';
const [widthsize, setWidthsize] = useState();
const [width, setWidth] = useState(hasWindow ? window.innerWidth : null);
let timeOutId = useRef();
useEffect(() => {
const handleResize = () => {
setWidth(window.innerWidth);
}
window.addEventListener('resize', () => {
clearTimeout(timeOutId.current);
timeOutId.current = setTimeout(handleResize, 500);
});
}, []);
useEffect(() => {
if (width !== null && width < 500) {
setWidthsize(300)
} else if (width !== null && width > 500) {
setWidthsize(1000)
} else {
setWidthsize(100)
}
}, [width])
return (
<div className="App">
<h1>{widthsize}</h1>
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
}