You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-leaflet+Geoman加载API GeoJSON多边形,点击编辑顶点消失

解决react-leaflet + Geoman多边形顶点消失问题

问题根源

  1. 用index作为组件key:多边形数组变化时,React会复用组件实例,新旧多边形状态混淆,引发顶点丢失。
  2. 重复创建多边形实例:useEffect依赖coordinates,每次坐标更新都会新建多边形,旧实例清理不彻底,编辑状态未同步,导致顶点显示异常。
  3. 重复绑定点击事件:每次useEffect执行都绑定一次点击事件,多次点击会触发多次toggleEdit,造成编辑状态混乱。

修复步骤

1. 替换key为唯一标识

放弃使用数组index作为组件key,改用多边形的唯一ID(比如后端返回的id字段),确保每个Polygon组件实例稳定:

{polygons.map((polygon) => (
  <Polygon 
    key={polygon.id} 
    coordinates={polygon.geometry.coordinates}
    onUpdate={(newCoords) => handlePolygonUpdate(polygon.id, newCoords)}
  />
))}

2. 稳定多边形实例,避免重复创建

用useRef保存多边形实例,仅在首次渲染时创建,后续坐标更新时直接修改现有实例的坐标,并同步编辑状态:

function Polygon({ coordinates, onUpdate }) {
  const context = useLeafletContext();
  const polygonRef = useRef(null);

  useEffect(() => {
    // 首次渲染创建多边形
    if (!polygonRef.current) {
      polygonRef.current = L.polygon(coordinates).addTo(context.map);

      // 仅绑定一次点击事件
      polygonRef.current.on('click', () => {
        polygonRef.current.pm.toggleEdit({
          snappable: true,
          draggable: true,
        });
      });

      // 监听编辑完成事件,同步坐标到父组件
      polygonRef.current.on('pm:edit', (e) => {
        onUpdate?.(e.layer.getLatLngs());
      });
    } else {
      // 坐标更新时,先保存编辑状态,更新后恢复
      const isEditing = polygonRef.current.pm.enabled();
      if (isEditing) polygonRef.current.pm.toggleEdit();
      polygonRef.current.setLatLngs(coordinates);
      if (isEditing) polygonRef.current.pm.toggleEdit({ snappable: true, draggable: true });
    }

    // 清理:移除多边形并关闭编辑
    return () => {
      if (polygonRef.current) {
        if (polygonRef.current.pm?.enabled()) polygonRef.current.pm.toggleEdit();
        context.map.removeLayer(polygonRef.current);
        polygonRef.current = null;
      }
    };
  }, [coordinates, context.map, onUpdate]);

  return null;
}

3. 同步编辑后的坐标到父组件

在父组件实现坐标更新逻辑,确保组件接收的coordinates与地图上的多边形状态一致:

function Map() {
  const [polygons, setPolygons] = useState([]); // 存储从API获取的多边形数据

  const handlePolygonUpdate = (polygonId, newCoords) => {
    setPolygons(prev => prev.map(p => 
      p.id === polygonId 
        ? {...p, geometry: {...p.geometry, coordinates: newCoords}} 
        : p
    ));
  };

  return (
    <MapContainer
      id="mapId"
      doubleClickZoom={false}
      style={{ height: "100vh" }}
      center={[-23.1573924, -45.7908461]}
      zoom={18}
      scrollWheelZoom={true}
    >
      {polygons.map((polygon) => (
        <Polygon 
          key={polygon.id} 
          coordinates={polygon.geometry.coordinates}
          onUpdate={(newCoords) => handlePolygonUpdate(polygon.id, newCoords)}
        />
      ))}
    </MapContainer>
  );
}

额外注意事项

  • 确保Geoman与react-leaflet版本兼容,避免版本冲突引发异常。
  • 清理函数必须移除地图上的多边形图层,防止旧图层残留导致交互混乱。

内容的提问来源于stack exchange,提问作者talison Brendon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:10:27