user6329530
user6329530

Reputation: 734

How do I get the width of a div in a window after it got rendered by react?

I am trying to get the size of a div (css width: 100%) and set the zoom factor of a component according to the div's size. The problem is on first run of the App, the div doesn't exist in the DOM yet, since return has not created it. So I tried to put it in a useEffect to check if it gets created. However for some reason this doesn't work, when I put the querySelector into a constant because I thought the constant would be recreated once the component renders again because useEffect should trigger a re-render. When I put it directly into the deps, I get a warning about exhaustive deps.

React Hook useEffect has a complex expression in the dependency array. Extract it to a separate variable so it can be statically checked  react-hooks/exhaustive-deps

How do I properly extract the querySelector into a variable to have the app react to it being rendered?

const App = () => {
    const querySelector = document.querySelector(".area-main"); //doesn't exist on 1st render but should be recreated on second render?
    const [zoom, setZoom] = useState(1);

    useEffect(() => {
        if(querySelector && querySelector.clientWidth > 1000){
            setZoom(1.5);
        }
        console.log(querySelector); // null
    }, [querySelector]); //chould change on re-render from null to element but doesn't trigger
    // the following works but complains about complex dependency tells me to extract (how?)
    //}, [document.querySelector(".area-main")]);

    useEffect(() => {
        console.log(zoom); //prints out 1 once
    }, [zoom]);

    return(
        <div className=".area-main">
            <Component zoom={zoom} />
        </div>
    );
}

According to the comment, I tried using layout effect but that doesn't change

const querySelector = document.querySelector(".canvas-main");

React.useLayoutEffect(() => {
    console.log(querySelector); //prints out null once
}, [querySelector]);

Upvotes: 2

Views: 6886

Answers (1)

Nicholas Tower
Nicholas Tower

Reputation: 84902

To get a reference to the div element, you'll want to use a react ref. Then you can access that ref in a useLayoutEffect and do what you need to do. useLayoutEffect is similar to useEffect, except if you set state it will cause a synchronous rerender, and that way you won't have a flicker on the screen as you reposition things.

const App () => {
  const [zoom, setZoom] = useState(1);
  const divRef = useRef();

  useLayoutEffect(() => {
    if (divRef.current.clientWidth > 1000) {
      setZoom(1.5)
    }
  }, []);

  return (
    <div ref={divRef} className=".area-main">
      <Component zoom={zoom} />
    </div>
  );
}

For more information on refs, see this page

Upvotes: 3

Related Questions