Reputation: 734
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
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