如何使用 react + redux 在传单 v3 中获取地图属性和处理事件?

How to get map properties and handle events in leaflet v3 with react + redux?

我是 React redux(和 hooks)的新手,我一直在关注 this 一般教程:

我也对使用 react-leaflet 很感兴趣,在撰写本文时它是在使用 hooks 的 v3 上。我已经能够加载包含 latlng 数组的数据以生成标记:

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { Map, MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
import { Icon } from "leaflet";
import "../../css/app.css";
import { useSelector, useDispatch } from "react-redux";
import { getMarkers, selectMarkers } from "../features/markerSlice";

export const LeafMap = () => {
    //marker state
    const stateMarker = useSelector(state => state.marker);
    const dispatch = useDispatch();
    useEffect(() => {dispatch(getMarkers());}, [dispatch]);

    // map state
    const stateMap = useSelector(state => state.map)

    if (stateMarker.markers.length > 0) {
        return (
            <MapContainer center={stateMap.center} zoom={stateMap.zoom} scrollWheelZoom={true}>
              <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
              {stateMarker.markers.map(el => (
                <Marker position={[el.latitude, el.longitude]}/>
              ))}
            </MapContainer>
        );
    } else {
        return (
            <MapContainer center={stateMap.center} zoom={stateMap.zoom} scrollWheelZoom={true}>
              <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
            </MapContainer>
        );
    }

}

目前,我对如何处理点击事件(标记点击)以及访问地图状态(当前边界框、当前缩放级别等)感到很困惑。我遇到错误,例如我无法访问地图状态,除非它在子组件中,或者无法识别 onclick 处理程序等。

我希望最终能够做一些事情,例如根据缩放和边界框动态加载标记,然后单击标记以放大它。这可能是因为我是 React redux 和一般钩子的绝对起点。

我不是在寻找任何人来为我编写代码,但如果有人可以提供有关如何完成这些代码的一般指导,我将不胜感激!

要处理标记点击事件,请使用 eventHandlers 道具并在 Markers comp 上收听点击事件,如下所示:

const CustomMarkers = () => {
    const map = useMap();
    return markers.map((el, i) => (
      <Marker
        key={i}
        position={[el.latitude, el.longitude]}
        icon={icon}
        eventHandlers={{
          click: () => {
            console.log("marker clicked", el);
            console.log(map.getZoom());
          }
        }}
      />
    ));
  };

您可以像这样导出每个标记元素,并在单击每个标记时使用 useMap 挂钩获取有关地图的信息。

根据缩放级别动态加载标记。一个例子可能是这样的: 你有一个 btn。当您单击它时,您会动态添加一个标记,该标记具有一个事件侦听器以进一步缩放地图。例如,仅当当前地图缩放级别为 6 时才会触发此事件。

 function AddMarkerOnClick({ map }) {
        const onClick = () => {
          console.log(map.getZoom());
          if (map?.getZoom() === 6) {
            L.marker([39.77, -106.23], { icon })
              .addTo(map)
              .addEventListener("click", () => map.setZoom(4));
          }
        };
    
        return <button onClick={onClick}>Add marker on click</button>;
      }

...
return (
<>
      <AddMarkerOnClick map={map} />
      <MapContainer
        center={position}
      ...
</>
)

为了能够获取地图参考,您需要将自定义组件作为子组件置于 MapContainer 之下,或者使用 MapContainer 的 whenCreated 道具获取 map instance,然后将其传递您的定制版。

示例Demo

在 react-leaflet v3 中,如果你想在另一个应用程序中使用地图及其属性,或者想从另一个组件向地图添加一些东西,你可以使用这个技巧:

class MapComponent extends Component {
    constructor(props) {
    super(props);
    this.mapRef = React.createRef();
}
render() {
return (
   <div>    
       <MapContainer whenCreated={ mapInstance => { this.mapRef.current =mapInstance }}>
       </MapContainer>
       <AnotherComponent map = {this.mapRef}/>
   </div>}
}

class AnotherApp extends React.Component {
     //access the map with: 
     this.props.map
}