I just updated my react-leaflet package from 2.7.0 to 3.1.0. Everything was fine with the older version. But when I upgraded the version to 3.1.0, I am unable to create the ref in <MapContainer />. My map container will appear in bootstrap modal, so it needed to be run invalidateSize function as below,
this.mapRef.current.leafletElement.invalidateSize(false)
But the mapRef always returning null. In previous version it was working fine.
<MapContainer
ref={this.mapRef}
center={[38.861, 71.2761]}
zoom={5}
zoomControl={false}
style={{ width: "100%", height: "70vh" }}
>
<ZoomControl position="topright" />
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
/>
</MapContainer>
The map ref value should not be none.
My constructor is here for creating the ref
import React, { Component } from "react";
import {
MapContainer,
TileLayer,
ZoomControl,
WMSTileLayer,
} from "react-leaflet";
class EarList extends Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}
onViewClick = (id) => {
this.setState({
id: id,
layer_name: ear.name,
});
setTimeout(
() => this.mapRef.current.leafletElement.invalidateSize(false),
1000
);
};
render() {
<button onClick={this.onViewClick.bind(this, id)} />
{/* onViewClick bootstrap model */}
<div className="modal fade map " tabIndex="-1" id="map">
<div className="modal-dialog modal-lg">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title text-center"> layer</h5>
<button
type="button"
className="close"
data-dismiss="modal"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
</div>
<MapContainer
ref={this.mapRef}
center={[38.861, 71.2761]}
zoom={5}
zoomControl={false}
style={{ width: "100%", height: "70vh" }}
>
<ZoomControl position="topright" />
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
/>
</MapContainer>
</div>
</div>
</div>
};
};
Hi @iamtekson,
Please see this issue for background https://github.com/PaulLeCam/react-leaflet/issues/806. Using a ref to access the map instance is no longer possible. My suggestion is to use the whenCreated prop to save a copy of the map instance to state and then use it as you normally would. Something like this should work in you case.
```javascript
import React, { Component } from "react";
import {
MapContainer,
TileLayer,
ZoomControl,
WMSTileLayer,
} from "react-leaflet";
class EarList extends Component {
constructor(props) {
super(props);
this.mapRef = React.createRef();
}
onViewClick = (id) => {
this.setState({
id: id,
layer_name: ear.name,
});
// first check mapRef.current is not not then proceed with the timeout
setTimeout(
() => this.mapRef.current.leafletElement.invalidateSize(false),
1000
);
};
render() {
{/* onViewClick bootstrap model */}
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors"
/>
</MapContainer>
</div>
</div>
</div>
};
};
```
Hi @Rennzie, Thank you very much for the solution. Now it is working fine without issue. In my case, I can access the set the invalidateSize to false as following,
//leafletElement no longer in use
setTimeout(
() => this.mapRef.current.invalidateSize(false),
1000
);
In my case, I can access the set the invalidateSize to false as following...
Agree, no need for leafletElement in mapRef.current.leafletElement e.g. - it's implicated in mapInstance already.
Hello, I have a similar issue upgrading from v2 to v3. I already tried to following previous suggestion on this thread and also what is reported here, but without consistent result.
I am using tangramjs, gatsbyjs and leaflet and till react-leaflet v2 I did not experience issues, but after upgrading to v3 I am unable to get a ref to MapContainer component.
With v2 I did like that:
const MapGeoviz = () => {
const mapRef = useRef();
useEffect(() => {
if (typeof window !== 'undefined'l) {
const layer = Tangram.leafletLayer({
scene,
});
layer.addTo(mapRef.current.leafletElement);
}
}, []);
if (typeof window !== 'undefined') {
return (
<Map
{...mapSettings}
ref={mapRef}
/>
);
}
return null;
};
Upgrading to v2 I try something like that following that:
const MapGeoviz = () => {
const [map, setMap] = useState(null);
useEffect(() => {
if (typeof window !== 'undefined' && map !== null) {
const layer = Tangram.leafletLayer({
scene,
});
layer.addTo(map);
}
}, [map]);
if (typeof window !== 'undefined') {
return (
<MapContainer
{...mapSettings}
whenCreated={setMap}
/>
);
}
return null;
};
Doing like that I am experience no consistency, because sometime tangram layer has been rendered and others not completely.
Following this thread I also try like that:
const MapServices = () => {
const mapRef = useRef();
useEffect(() => {
if (typeof window !== 'undefined') {
const layer = Tangram.leafletLayer({
scene,
});
layer.addTo(map.current);
}
}, []);
if (typeof window !== 'undefined') {
return (
<MapContainer
{...mapSettings}
whenCreated={(mapInstance)=> { mapRef.current = mapInstance }}
/>
);
}
return null;
};
With this solution I always get an undefined reference to map in layer.addTo(map.current);. If I also add map !== undefined to if statement inside useEffect, it does not rendering layer, so I think it does not get any ref.
I am doing something wrong, but can you point me how can I fix that?
Thanks!
Hi @lezan,
You'd be better of asking on Stack Overflow. The maintainer doesn't offer support in the issues. That said,
I'd roll your Tangram layer into a custom component and nest it within the map. Something like:
import {useMap} from 'react-leaflet';
const TangramLayer = () => {
const map = useMap()
useEffect(() => {
if (typeof window !== 'undefined') {
const layer = Tangram.leafletLayer({
scene,
});
layer.addTo(map.current);
}
}, [map]);
return null
}
const MapServices = () => {
return (
<MapContainer {...mapSetting} >
<TangramLayer />
</MapContainer>
)
}
This blog of mine may give you some other ideas
Hello @Rennzie, I thought it might be related to what was also posted in this thread, sorry about that.
Meanwhile I found a similar solution using createTileLayerComponent and with a Tangram component nest it within the <MapContainer /> component. I followed this docs. I think it could be good as your solution, by the way I will give a try to your, because it is much simpler.
I really appreciate your answer, thanks! And sorry again for posting here.
No worries at all @lezan, only hoping you get an answer faster there.
I was also going to suggest trying a custom component, but glad you've got what you need.
Best of luck.
Most helpful comment
Hi @Rennzie, Thank you very much for the solution. Now it is working fine without issue. In my case, I can access the set the invalidateSize to false as following,