首页 > 解决方案 > Add onClick on MapContainer in Component in 3.x

问题描述

I'm using the following versions:

"leaflet": "^1.7.1",
"react-leaflet": "^3.0.2",

I want to perform some action on map-click, e.g. add a marker.

I tried the stateless component approach which seems to work, but I don't really like it for several reasons.

I tried using eventHandlers attribute:

  render() {
    return <div>
          <MapContainer center={[ 48, 11 ]} zoom={10} scrollWheelZoom={true} eventHandlers={{
            click: () => {
              console.log('map clicked')
            },
          }}>
            <TileLayer .../>
          </MapContainer>
        </div>
  }

but it never fires.

I also read about MapConsumer but can't find good examples to it.

Any hints on building in onClick event handler are appreciated.

TIA

标签: javascriptreactjsleafletreact-leaflet

解决方案


It seems that eventHandlers, although it is available as a prop on MapContainer (if you press ctlr + space on vscode f.i it will pop up) it is not available in the official API and is intended only for child components of MapContainer, see here and here for Marker.

what you want to achieve can be implemented using useMapEvents on a separate comp and then included as a child on MapContainer:

function App() {
  function MyComponent() {
    const map = useMapEvents({
      click: (e) => {
        const { lat, lng } = e.latlng;
        L.marker([lat, lng], { icon }).addTo(map);
      }
    });
    return null;
  }

  return (
    <MapContainer center={[50.5, 30.5]} zoom={13} style={{ height: "100vh" }}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <MyComponent />
    </MapContainer>
  );
}

Demo

Another approach is listen to whenReady prop (not officially documented but seems to work similarly to whenCreated prop but map instance is accessible via object.target) on MapContainer:

<MapContainer
      center={[50.5, 30.5]}
      zoom={13}
      style={{ height: "100vh" }}
      whenReady={(map) => {
        console.log(map);
        map.target.on("click", function (e) {
          const { lat, lng } = e.latlng;
          L.marker([lat, lng], { icon }).addTo(map.target);
        });
      }}
    >
    ...
</MapContainer>

3rd approach is to use MapConsumer as a child of MapContainer (docs):

<MapContainer center={[50.5, 30.5]} zoom={13}>
     <MapConsumer>
            {(map) => {
              console.log("map center:", map.getCenter());
              map.on("click", function (e) {
                const { lat, lng } = e.latlng;
                L.marker([lat, lng], { icon }).addTo(map);
              });
              return null;
            }}
     </MapConsumer>
</MapContainer>

4th approach is to use whenCreated prop (officially documented) on MapContainer:

<MapContainer
      center={[50.5, 30.5]}
      zoom={13}
      style={{ height: "100vh" }}
      whenCreated={(map) => {
        map.on("click", function (e) {
          const { lat, lng } = e.latlng;
          L.marker([lat, lng], { icon }).addTo(map.target);
        });
      }}
    >
...

推荐阅读