I'm trying to execute this react-leaflet
example: https://react-leaflet.js.org/docs/example-react-control/
This is the code:
import * as React from 'react';
import * as leaflet from 'leaflet'
import { MapContainer, TileLayer, Marker, Popup, useMapEvent, useMap, Rectangle } from 'react-leaflet'
import { useEventHandlers } from '@react-leaflet/core'
import "leaflet/dist/leaflet.css"
import "leaflet/dist/images/marker-shadow.png"
import Box from '@mui/material/Box'
export default function Mapping(props) {
// Classes used by Leaflet to position controls
const POSITION_CLASSES = {
bottomleft: 'leaflet-bottom leaflet-left',
bottomright: 'leaflet-bottom leaflet-right',
topleft: 'leaflet-top leaflet-left',
topright: 'leaflet-top leaflet-right',
}
const BOUNDS_STYLE = { weight: 1 }
function MinimapBounds({ parentMap, zoom }) {
const minimap = useMap()
// Clicking a point on the minimap sets the parent's map center
const onClick = React.useCallback(
(e) => {
parentMap.setView(e.latlng, parentMap.getZoom())
},
[parentMap],
)
useMapEvent('click', onClick)
// Keep track of bounds in state to trigger renders
const [bounds, setBounds] = React.useState(parentMap.getBounds())
const onChange = React.useCallback(() => {
setBounds(parentMap.getBounds())
// Update the minimap's view to match the parent map's center and zoom
minimap.setView(parentMap.getCenter(), zoom)
}, [minimap, parentMap, zoom])
// Listen to events on the parent map
const handlers = React.useMemo(() => ({ move: onChange, zoom: onChange }), [])
useEventHandlers({ instance: parentMap }, handlers)
return <Rectangle bounds={bounds} pathOptions={BOUNDS_STYLE} />
}
function MinimapControl({ position, zoom }) {
const parentMap = useMap()
const mapZoom = zoom || 0
// Memoize the minimap so it's not affected by position changes
const minimap = React.useMemo(
() => (
<MapContainer
style={{ height: 80, width: 80 }}
center={parentMap.getCenter()}
zoom={mapZoom}
dragging={false}
doubleClickZoom={false}
scrollWheelZoom={false}
attributionControl={false}
zoomControl={false}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<MinimapBounds parentMap={parentMap} zoom={mapZoom} />
</MapContainer>
),
[],
)
const positionClass =
(position && POSITION_CLASSES[position]) || POSITION_CLASSES.topright
return (
<div className={positionClass}>
<div className="leaflet-control leaflet-bar">{minimap}</div>
</div>
)
}
return (
<div>
<h3>Map</h3>
<div id="map">
<MapContainer
center={[51.505, -0.09]}
zoom={13}
scrollWheelZoom={false}
style={{ height: '100vh', width: '100wh' }}
>
<TileLayer
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[51.505, -0.09]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
</div>
</div>
)
I'm getting this error message:
src/app_D/components/mapVisualize/maps.tsx:54:22 - error TS2345: Argument of type '{ instance: any; }' is not assignable to parameter of type 'LeafletElement<Evented, any>'.
Property 'context' is missing in type '{ instance: any; }' but required in type 'LeafletElement<Evented, any>'.
54 useEventHandlers({ instance: parentMap }, handlers)
~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@react-leaflet/core/types/element.d.ts:5:5
5 context: LeafletContextInterface;
~~~~~~~
'context' is declared here.
src/app_D/components/mapVisualize/maps.tsx:104:10 - error TS2741: Property 'zoom' is missing in type '{ position: string; }' but required in type '{ position: any; zoom: any; }'.
104 <MinimapControl position="topright" />
~~~~~~~~~~~~~~
If I "convert" the file to a javascript file: maps.tsx
-> maps.js
, then it works fine:
So it must be something related to typescript types
Other info:
"@types/leaflet": "^1.7.8"
"leaflet": "^1.7.1"
"webpack": "^5.23.0"
"react": "^17.0.2"
"react-leaflet": "^3.2.5"
node: v16.13.0
O.S.: Ubuntu 20.04 Desktop
How to solve the problem?
The definition of LeafletElement in element.d.ts is:
export interface LeafletElement<T, C = any> {
instance: T;
context: LeafletContextInterface;
container?: C | null;
}
Which indicates that context
is a required element. But the usage of useEventHandlers
in the examples for react-leaflet seem to indicate that context
is not required. I filed a bug report here.
You can workaround the issue with useLeafletContext
and then using it in the call to useEventHandlers
:
const context = useLeafletContext();
// ... rest of code removed for brevity
useEventHandlers({instance: parentMap, context}, handlers);