0

Someone can help me? I'd be really thankful :) The problem here is that when the width and height changes, the UseEffect doesn't run again. This is a textarea that is being resized...

const [elem, setElem] = useState<HTMLElement>(document.createElement('textarea'))
const width = window.getComputedStyle(elem, null).getPropertyValue("width");
const height = window.getComputedStyle(elem, null).getPropertyValue("height");

   useEffect(() => {
      setElem(document.getElementById("email") as HTMLElement) 
      console.log(width, height)
   },[elem, width, height])
  • You're only getting those values when the component re-renders. Just because the window is resized, doesn't mean a component will re-render. You should add an resizing event listener to the window (or text area element) that stores the new width/height in state. That will trigger a re-render – Jayce444 Oct 28 '20 at 00:40

2 Answers2

0

set the width and height using the useState.

const [width, setWidth] = useState(undefined);
const [height, setHeight] = useState(undefined);


useEffect(() => {
  const getWidth = () => window.getComputedStyle(elem, null).getPropertyValue("width");

  const getHeight = () => window.getComputedStyle(elem, null).getPropertyValue("height");
  const resizeListener = () => {
      setWidth(getWidth())
      setHeight(getHeight())
    };

  window.addEventListener('resize', resizeListener);

  resizeListener();
  // Don't foget cleanup!
  return () => window.removeEventListener('resize', resizeListener);
  // There's a dependency on the element, so if that changes, re-run the effect
}, [elem])


Attach the resize event listener and update width and height using setWidth and setHeight.

Zachary Haber
  • 10,376
  • 1
  • 17
  • 31
wangdev87
  • 8,611
  • 3
  • 8
  • 31
0

@William-wang has the right idea. Your code wouldn't retrigger the effect because the values never change except potentially when the code re-renders for other reasons.

While his method using a resize listener on the window will update the width and height, it only happens when the window's size changes.

I've modified the code to use the newer Resize Observer api. More details in How to detect DIV's dimension changed?.

This way, it's possible to get accurate and up-to-date size changes. The only issue with this approach is that older browsers don't support it. Though it does seem to be supported by all modern main browsers at this point.

const { useState, useEffect, useRef } = React;
function Example() {
  const elemRef = useRef(null);
  const [width, setWidth] = useState(undefined);
  const [height, setHeight] = useState(undefined);

  useEffect(() => {
    if (!elemRef.current) {
      return;
    }
    const resizeListener = () => {
      setWidth(elemRef.current.offsetWidth);
      setHeight(elemRef.current.offsetHeight);
    };
    const observer = new ResizeObserver(resizeListener);
    observer.observe(elemRef.current);
    // Don't foget cleanup!
    return () => observer.disconnect();
  }, []);

  return (
    <div>
      width: {width}
      <br />
      height: {height}
      <br />
      <textarea ref={elemRef} />
    </div>
  );
}

ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Zachary Haber
  • 10,376
  • 1
  • 17
  • 31