I am using this hook to measure the size of a div component (https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node):
function useClientRect() {
const [rect, setRect] = React.useState(null);
const ref = React.useCallback(node => {
if (node !== null) {
setRect(node.getBoundingClientRect());
}
}, []);
return [rect, ref];
}
This is my component, simplified. I'm using it along with React Map GL, as there is no way to set the width of the viewport in terms of %. I couldn't find other way to do it... getBoundsForPoints is a function to obtain the limits of the viewport of a map, given an array of coordinates and the width of the map in pixels.
function Mapas(props){
const [rect,ref] = useClientRect()
useEffect(()=>{
const coordinates = [some coordinates]
let new_viewport
if (rect!==null){ //Here is when sometimes I get rect===null
new_viewport = getBoundsForPoints(coordinates, rect.width)
} else {
new_viewport = getBoundsForPoints(coordinates, 500)
}
setViewport(new_viewport)
},[rect])
return (
<MDBContainer>
<MDBRow>
<MDBCol md='12' xl='8'>
<div ref={ref}> {/*Elemento referenciado */}
<ReactMapGL
{...viewport}
mapboxApiAccessToken='xxx'}
mapStyle='xxx'
onViewportChange={nextViewport => setViewport({...nextViewport})}
>
</ReactMapGL>
</div>
</MDBCol>
<MDBCol xl='4' md='12'>
Other stuff
</MDBCol>
</MDBRow>
</MDBContainer>
)
}
export default Mapas
When the page is loaded it's working fine; however, when I get to the page from other component, without re-rendering, rect is null. How can I avoid this, thank you!
I finally had to use the hook useLayoutEffect, instead of useEffect. The hook (https://es.reactjs.org/docs/hooks-reference.html#uselayouteffect) is similar to useEffect but is run after all components are built, therefore the reference is now correctly defined and can measure the dimensions of the component. The final simplified code is the following:
function useClientRect() {
const [rect, setRect] = React.useState(null);
const ref = React.useCallback(node => {
console.log('Node')
console.log(node)
if (node !== null) {
setRect(node.getBoundingClientRect());
}
}, []);
return [rect, ref];
}
function Mapas(props){
const [rect,ref] = useClientRect()
useLayoutEffect(()=>{
const coordinates = [some coordinates]
let new_viewport
if (rect!==null){ //Here is when sometimes I get rect===null
new_viewport = getBoundsForPoints(coordinates, rect.width)
} else {
new_viewport = getBoundsForPoints(coordinates, 500)
}
setViewport(new_viewport)
},[rect])
return (
<MDBContainer>
<MDBRow>
<MDBCol md='12' xl='8'>
<div ref={ref}> {/*Elemento referenciado */}
<ReactMapGL
{...viewport}
mapboxApiAccessToken='xxx'}
mapStyle='xxx'
onViewportChange={nextViewport => setViewport({...nextViewport})}
>
</ReactMapGL>
</div>
</MDBCol>
<MDBCol xl='4' md='12'>
Other stuff
</MDBCol>
</MDBRow>
</MDBContainer>
)
}
export default Mapas