I'm trying to replicate some functions of the leaflet map https://leafletjs.com/examples/choropleth/ to react/typeScript but I'm getting an error when I try to add the function to zoom on a Feature it breaks, this is the code I'm working on
import Leaflet from 'leaflet';
import React, {
useRef, RefObject,
} from 'react';
import {
MapContainer, TileLayer, GeoJSON, useMap,
} from 'react-leaflet';
import styled from 'styled-components';
import { statesData } from './statesData';
import './style.css';
const EmployerLocationMap = () => {
const geoJson: RefObject<Leaflet.GeoJSON> = useRef(null);
const map = useMap();
const highlightFeature = (e: Leaflet.LeafletMouseEvent) => {
const layer = e.target;
layer.setStyle({
color: '#666',
dashArray: '',
fillOpacity: 0.7,
weight: 5,
});
};
const resetHighlight = (e: Leaflet.LeafletMouseEvent) => {
geoJson.current?.resetStyle(e.target);
};
const zoomToFeature = (e: Leaflet.LeafletMouseEvent) => {
map.fitBounds(e.target.getBounds());
};
return (
<CardContainer>
<Row>
<Col width='60%'>
<MapContainer
center={[37.8, -96]}
zoom={3}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
<GeoJSON
data={statesData}
key='usa-states'
ref={geoJson}
style={() => {
return {
color: 'white',
dashArray: '3',
fillColor: '#f0f0f0',
fillOpacity: 0.7,
opacity: 1,
weight: 2,
};
}}
onEachFeature={(__, layer) => {
layer.on({
click: (e) => {
zoomToFeature(e);
},
mouseout: (e) => {
resetHighlight(e);
},
mouseover: (e) => {
highlightFeature(e);
},
});
}}
/>
</MapContainer>
</Col>
</Row>
</CardContainer>
);
};
export default EmployerLocationMap;
and when I start the frontend i get this error on the console:
Uncaught Error: No context provided: useLeafletContext() can only be used in a descendant of
<MapContainer>
at useLeafletContext
I don't get what could be wrong, I've seen several implementations on this and it looks the same.
CodePudding user response:
useMap
can only be used within a component that is itself a child/descendant of <MapContainer>
.
https://react-leaflet.js.org/docs/api-map/#usemap
Hook providing the Leaflet Map instance in any descendant of a
MapContainer
.
Here you try calling useMap
in your EmployerLocationMap
component, which contains a <MapContainer>
, but which is obviously not a descendant of one.
A solution for your case could be to separate the map logic in another component that you can place inside the <MapContainer>
:
const EmployerLocationMap = () => {
return (
<CardContainer>
<Row>
<Col width='60%'>
<MapContainer
center={[37.8, -96]}
zoom={3}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
<MapContent />
</MapContainer>
</Col>
</Row>
</CardContainer>
);
};
const MapContent = () => {
const geoJson: RefObject<Leaflet.GeoJSON> = useRef(null);
const map = useMap();
const highlightFeature = (e: Leaflet.LeafletMouseEvent) => {
const layer = e.target;
layer.setStyle({
color: '#666',
dashArray: '',
fillOpacity: 0.7,
weight: 5,
});
};
const resetHighlight = (e: Leaflet.LeafletMouseEvent) => {
geoJson.current?.resetStyle(e.target);
};
const zoomToFeature = (e: Leaflet.LeafletMouseEvent) => {
map.fitBounds(e.target.getBounds());
};
return (
<GeoJSON
data={statesData}
key='usa-states'
ref={geoJson}
style={() => {
return {
color: 'white',
dashArray: '3',
fillColor: '#f0f0f0',
fillOpacity: 0.7,
opacity: 1,
weight: 2,
};
}}
onEachFeature={(__, layer) => {
layer.on({
click: (e) => {
zoomToFeature(e);
},
mouseout: (e) => {
resetHighlight(e);
},
mouseover: (e) => {
highlightFeature(e);
},
});
}}
/>
);
};