2

I am trying to access the window object inside of a React.js component as I want to create a state which holds the dynamic innerWidth value of the window object. I was able to make it work when the page gets refreshed but not when I resize the page with the dev tools dynamically.

Here is the code that works for me on refresh:

const About = () => {

  const [bioType, setBioType] = useState("");

  const truncateText = () =>
    window.innerWidth > 1024 ? setBioType("desktop") : setBioType("mobile");

  useEffect(() => {
    truncateText();
  });

  return ({
    bioType === 'desktop' ? ... : ....
  })

}

However, when I resize the web page with Dev Tools, it doesn't work. Could someone give me a hint? Thanks.`

Matt Morgan
  • 4,900
  • 4
  • 21
  • 30
  • Your component is not listening and is not aware of window size changes. You will need to listen for the window size to change, probably using a ResizeObserver: https://stackoverflow.com/a/39312522/3084820. It's not likely that the problem is actually that you can't access the window object. Are you getting an error that indicates that's the case? – Matt Morgan Feb 03 '23 at 20:30
  • I've edited the title of your question to better reflect the actual problem. I expect that will make it more discoverable by the next person who has this problem. – Matt Morgan Feb 03 '23 at 21:16

1 Answers1

2

Changing the windows width doesn't cause React to react to the change, and re-render. You need to use an event handler to listen to the resize event, use a ResizeObserver or use MatchMedia, and listen to the changes.

Example with MatchMedia:

const { useState, useEffect } = React;

const MIN_WIDTH = 600;

const getBioType = matches => matches ? 'desktop' : 'mobile';

const About = () => {
  const [bioType, setBioType] = useState(() => getBioType(window.innerWidth > MIN_WIDTH));

  useEffect(() => {
    const mql = window.matchMedia(`(min-width: ${MIN_WIDTH}px)`);
    
    const handler = e => setBioType(getBioType(e.matches));
    
    mql.addEventListener('change', handler);
    
    return () => {
      mql.removeEventListener('change', handler);
    };
  }, []);

  return bioType;
}

ReactDOM
  .createRoot(root)
  .render(<About />);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>

<div id="root"></div>
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • TIL `matchMedia`! Nice. – Matt Morgan Feb 03 '23 at 20:37
  • @MattMorgan - thanks. I've included `ResizeObserver` as well due to your comment. – Ori Drori Feb 03 '23 at 20:38
  • maybe worth mentioning that your demo code _might_ need to be viewed in full screen mode, as I think the running snippet is in an iframe, and will show `mobile` even at fairly wide screen widths (since it's watching the width of the embedded iframe, not the browser window.) Depends on the viewer's setup of course... – Matt Morgan Feb 03 '23 at 20:46
  • 1
    Good point. I've reduce the example's `MIN_WIDTH` to 600. – Ori Drori Feb 03 '23 at 20:56