-
-
Save gragland/4e3d9b1c934a18dc76f585350f97e321 to your computer and use it in GitHub Desktop.
import { useState, useEffect } from 'react'; | |
// Usage | |
function App() { | |
const size = useWindowSize(); | |
return ( | |
<div> | |
{size.width}px / {size.height}px | |
</div> | |
); | |
} | |
// Hook | |
function useWindowSize() { | |
// Initialize state with undefined width/height so server and client renders match | |
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/ | |
const [windowSize, setWindowSize] = useState({ | |
width: undefined, | |
height: undefined, | |
}); | |
useEffect(() => { | |
// Handler to call on window resize | |
function handleResize() { | |
// Set window width/height to state | |
setWindowSize({ | |
width: window.innerWidth, | |
height: window.innerHeight, | |
}); | |
} | |
// Add event listener | |
window.addEventListener("resize", handleResize); | |
// Call handler right away so state gets updated with initial window size | |
handleResize(); | |
// Remove event listener on cleanup | |
return () => window.removeEventListener("resize", handleResize); | |
}, []); // Empty array ensures that effect is only run on mount | |
return windowSize; | |
} |
When I use this hook twice, it adds Event Listener to window twice. Should this be adding only once and Event caching needed ?
react_devtools_backend.js:6 ./src/utils/useWindowSize.js
Line 27:6: React Hook useEffect has missing dependencies: 'getSize' and 'isClient'. Either include them or remove the dependency array react-hooks/exhaustive-deps
Hello! 👋🏻
This code has an issue with server rendering. I ran in to a similar issue here: gatsbyjs/gatsby#14601
The underlying issue is in getSize
return {
width: isClient ? window.innerWidth : undefined,
height: isClient ? window.innerHeight : undefined
};
The problem is that the server render value of windowSize
and the first client render won't match. (eg, width
on the server will be undefined
, client will be window.innerWidth
). This confuses React and you will see incorrect values on first load, as described in the github issue above and demonstrated here on a large screen: http://mikelambert.me/gatsby-bug/
To fix this, I modified the hook to always initialize the values to undefined
(so the server render and first client render match) and to update the values after the first render on the client.
export default function useWindowSize() {
// initialize to undefined so the server render and first client render match
// https://github.com/gatsbyjs/gatsby/issues/14601
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener("resize", handleResize);
handleResize();
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
}
change the useEffect
to useLayoutEffect
because you see a flicker before it's set in some cases. useLayoutEffect
is definitely the way to go here. Here an example where a div is centered based on the body, if you change it to a normal useEffect
you will see it flicker. https://codesandbox.io/s/still-wave-q0pk7
Long time has passed , why haven't this been updated with debounce or throttle ?
Thanks for the reusable hook, it helped me a lot. As going head i thought of writing the test case for the useWindowSize hook.
so i was able to cover 90% but since i was also new to unit testing. anyone would have a fair knowledge how can we have 100% code coverage.
so the people won't need to write it again and again for the test case.
Also please suggest any better way, i was using enzyme and jest but since hooks support was less i was using react testing library.
@testing-library/react
@testing-library/react-hooks
so using act how can i make the window to a different data type rather than object so it will have 100% test coverage.
//hooks.js
// hooks.test.js