Implement a useWindowSize hook that returns the current height and width of the window (window.innerHeight and window.innerWidth). It should re-render the component if the window size changes.
export default function Component() {const screen = useWindowSize();return (<div><p>The current window dimensions are:</p><code>{JSON.stringify(screen, null, 2)}</code></div>);}
Nothing.
The hook returns an object with the following properties:
height: number: Current height of the windowwidth: number: Current width of the windowwindow.innerHeight and window.innerWidth, not from screen.resize events and clean up the listener when the hook unmounts.window exists.useWindowSize() returns a React state snapshot of the current viewport. The important detail is that the hook must measure once on mount, not wait for the first resize event. The snapshot starts with a placeholder value, is measured as soon as the hook mounts, and is refreshed whenever the browser fires resize.
useWindowSize caches window.innerWidth and window.innerHeight:
{ width, height } object that components render from.window.The lifecycle is intentionally front-loaded:
| Lifecycle point | State value | Listener state |
|---|---|---|
| Initial render | { width: 0, height: 0 } placeholder | Not attached yet |
| Layout effect runs | Real window.innerWidth / innerHeight | resize listener attached |
| Browser resizes | Updated from window | Same listener handles the event |
| Unmount | No further updates | Listener removed |
The hook initializes state with { width: 0, height: 0 } because the real viewport can only be read from the browser. Once mounted, the same resize handler is used for both the first measurement and later resize events:
const resize = () =>setWindowSize({height: window.innerHeight,width: window.innerWidth,});resize();window.addEventListener('resize', resize);
Calling resize() inside the effect means consumers do not have to wait for the first resize event before receiving the actual dimensions. Using useLayoutEffect lets that first browser measurement happen before paint, avoiding a visible render with the placeholder dimensions.
The cleanup removes the same handler from window when the component unmounts:
return () => {window.removeEventListener('resize', resize);};
The important tradeoff is freshness over throttling. This exercise updates on every resize event; a production hook might debounce that work, but it would still need the same immediate measurement and cleanup behavior.
import { useState, useLayoutEffect } from 'react';/*** @typedef {Object} WindowSize* @property {number} height* @property {number} width*/export default function useWindowSize() {const [windowSize, setWindowSize] = useState({height: 0,width: 0,});useLayoutEffect(() => {const resize = () =>setWindowSize({height: window.innerHeight,width: window.innerWidth,});// Measure once on mount so consumers do not wait for the first resize event.resize();window.addEventListener('resize', resize);return () => {window.removeEventListener('resize', resize);};}, []);return windowSize;}
Registering the listener is not enough. The hook should measure immediately on mount, otherwise the returned value stays { width: 0, height: 0 } until the user resizes the window.
removeEventListener() only removes the exact function reference that was registered. Define the handler once inside the effect and pass that same resize function to both addEventListener() and removeEventListener().
The question asks for the viewport size from window.innerWidth and window.innerHeight. Other APIs such as screen.width describe the physical screen and can differ from the browser viewport.
window exists.console.log() statements will appear here.