I have a React functional component that has a react-leaflet map being rendered on the server-side. The map shows perfectly, but when I add a click event handler function to pass to the parent component I am greeted with the error: Cannot destructure property 'MapContainer' of 'reactLeaflet' as it is null This is code in the child component:
const MyMap = (props, ref) => {
const [ reactLeaflet, setReactLeaflet ] = useState(null);
const [ position, setPosition ] = useState(null);
useEffect(() => {
const loadData = async () => {
// react-leaflet errors if imported server-side (with "ReferenceError: window is not defined")
// not sure if this load can happen in parallel with leaflet.js or not
import('react-leaflet')
.then(leaflet => setReactLeaflet(leaflet))
.catch(error => noticeError(null, levels.error, error, "react-leaflet failed to load"));
};
loadData();
}, []);
const {
MapContainer,
Marker,
Popup,
TileLayer,
useMapEvents,
} = reactLeaflet;
const HandleClickMap = (e) =>{
const currMap = useMapEvents({
click() {
currMap.locate();
},
locationfound(e) {
setPosition(e.latlng);
currMap.flyTo(e.latlng, currMap.getZoom());
},
});
return position === null ? null : ( <Marker position={position}></Marker> );
};
useImperativeHandle(ref, () => ({
HandleClickMap,
}));
if (!reactLeaflet) {
return <LeafletCss />;
}
return <>
<LeafletCss />
<MapContainer
center={{ lat: 0, lng: 0 }}
zoom={13}
ref={ref}
scrollWheelZoom={false}
className={style.mapContainer}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
<HandleClickMap />
</MapContainer>
</>;
};
export default forwardRef(MyMap);
This problem happened when I added in the useImperativeHandle hook. Any insight into why is appreciated.
Check if reactLeaflet
object has been imported before attempting to access its components
const MyMap = (props) => {
const {
MapContainer,
Marker,
Popup,
TileLayer,
useMapEvents,
} = props.reactLeaflet;
const [ position, setPosition ] = useState(null);
const HandleClickMap = (e) =>{
const currMap = useMapEvents({
click() {
currMap.locate();
},
locationfound(e) {
setPosition(e.latlng);
currMap.flyTo(e.latlng, currMap.getZoom());
},
});
return position === null ? null : ( <Marker position={position}></Marker> );
};
useImperativeHandle(props.ref, () => ({
HandleClickMap,
}));
return <>
<LeafletCss />
<MapContainer
center={{ lat: 0, lng: 0 }}
zoom={13}
ref={ref}
scrollWheelZoom={false}
className={style.mapContainer}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
<HandleClickMap />
</MapContainer>
</>;
}
const MapLoader = (props, ref) => {
const [ reactLeaflet, setReactLeaflet ] = useState(null);
useEffect(() => {
const loadData = async () => {
import('react-leaflet')
.then(leaflet => setReactLeaflet(leaflet))
.catch(error => noticeError(null, levels.error, error, "react-leaflet failed to load"));
};
loadData();
}, []);
return (reactLeaflet ?
<MyMap reactLeaflet={reactLeaflet} ref={ref} /> :
<LeafletCss />
);
};
export default forwardRef(MapLoader);