Back to React
React
medium
mid

How would you re render a React component when the window is resized?

Subscribe to the window resize event in a useEffect, store the dimension in state so a change triggers a re-render, and clean up the listener on unmount. Throttle/debounce the handler for performance. Extract it into a reusable useWindowSize hook; consider ResizeObserver for element-level sizing.

5 min read·~10 min to think through

React doesn't re-render on window resize automatically — window.innerWidth isn't reactive. You make it reactive by putting the value in state and updating it from a resize listener.

The hook

jsx
function useWindowSize() {
  const [size, setSize] = useState(() => ({
    width: window.innerWidth,
    height: window.innerHeight,
  }));

  useEffect(() => {
    const handleResize = () => {
      setSize({ width: window.innerWidth, height: window.innerHeight });
    };
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize); // cleanup!
    // empty deps — set up once
  }, []);

  return size;
}

Using it:

jsx
const { width } = useWindowSize();
return width < 768 ? <MobileNav /> : <DesktopNav />;

State change → re-render. Done.

The three things people get wrong

  1. No cleanup — not removing the listener in the effect's return leaks listeners on every mount/unmount.
  2. No throttle/debounceresize fires rapidly (dozens of events per second while dragging). Setting state on each one floods React with renders. Throttle (e.g. every ~100–150ms — keeps it responsive) or debounce (only after resize stops — cheaper) the handler.

``js const handleResize = throttle(() => setSize({...}), 150); // and: return () => { handleResize.cancel?.(); window.removeEventListener(...); } ``

  1. SSRwindow doesn't exist on the server. Guard the initializer, or initialize to a default and set the real value in useEffect (which only runs client-side). Beware hydration mismatch.

Better alternatives — often you don't need JS at all

  • CSS media queries / container queries — if you just need layout to change, do it in CSS. No re-render, no JS. This is the right answer most of the time.
  • window.matchMedia — if you need a boolean breakpoint in JS (isMobile), listen to a MediaQueryList instead of raw resize — it only fires when the breakpoint actually crosses, not on every pixel.
  • ResizeObserver — if you care about a specific element's size (not the window), this is the correct tool — it's element-scoped and more efficient.

How to answer

"Window dimensions aren't reactive, so I put them in state and update from a throttled resize listener inside a useEffect, with cleanup on unmount — packaged as a useWindowSize hook. But I'd first ask whether I even need JS: if it's purely layout, CSS media/container queries are better; if I need a JS boolean breakpoint, matchMedia; if I need an element's size, ResizeObserver."

Follow-up questions

  • Why throttle or debounce the resize handler?
  • When should you use CSS media queries instead of a resize listener?
  • What's the difference between matchMedia and listening to raw resize?
  • When is ResizeObserver the right tool instead?
  • How do you handle window not existing during SSR?

Common mistakes

  • Forgetting to remove the listener on unmount — listener leak.
  • Setting state on every resize event with no throttle/debounce.
  • Reading window.innerWidth directly and expecting re-renders.
  • Accessing window during SSR without a guard.
  • Using JS for something CSS media/container queries handle.

Performance considerations

  • resize fires very frequently — unthrottled state updates cause render storms. Throttle/debounce the handler. matchMedia fires only on breakpoint crossings, far cheaper. CSS media/container queries avoid JS and re-renders entirely.

Edge cases

  • SSR / hydration mismatch when window isn't available server-side.
  • Orientation change on mobile.
  • Rapid continuous resizing (window drag).
  • Element resizing independently of the window (use ResizeObserver).

Real-world examples

  • A useWindowSize / useMediaQuery hook switching between mobile and desktop navigation.
  • ResizeObserver driving a chart that must re-fit its container.

Senior engineer discussion

Seniors give the state + throttled-listener + cleanup hook, but lead with 'do you even need JS?' — CSS media/container queries for layout, matchMedia for JS booleans, ResizeObserver for element sizing. They flag SSR/hydration and the render-storm risk, showing they pick the cheapest tool for the actual need.

Related questions