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

React Leaflet Draw多边形编辑后状态更新异常问题求助

问题描述

我将多边形数组设为React状态,使用Leaflet展示并编辑多边形,后续需将状态存入数据库。当前问题:首次编辑现有多边形并保存时状态更新正常,但第二次编辑时,手柄可移动但多边形状态未更新。临时解决方法是第二次点击编辑按钮后取消,再重新点击编辑即可正常工作,但这并非合理方案。

相关代码:

import { useState } from "react";
import { MapContainer, TileLayer, FeatureGroup, Polygon } from "react-leaflet";
import { EditControl } from "react-leaflet-draw";
import "leaflet-draw/dist/leaflet.draw.css";

export default function Zones() {
    const _polygon1 = {
        id: 1,
        latlngs: [
            [51.515, 5.09],
            [52.52, 5.1],
            [51.52, 6.12],
        ],
    };
    const _polygon2 = {
        id: 2,
        latlngs: [
            [52, 6.09],
            [52.52, 6.1],
            [52.52, 7.12],
        ],
    };

    const [polygons, setPolygons] = useState([_polygon1, _polygon2]);

    const onEdited = (layers) => {
        //polygons that are changed are stored in changedPolys array
        const changedPolys = Object.values(layers._layers).map((layer) => {
            const latlngs = layer._latlngs[0].map((latlng) => {
                return [latlng.lat, latlng.lng];
            });
            return { id: layer.options.id, latlngs: latlngs };
        });

        //update state of all the polygons. replace polygons with changedPolys
        changedPolys.forEach((changedPoly) => {
            setPolygons((polygons) => {
                return polygons.map((polygon) => {
                    if (polygon.id === changedPoly.id) {
                        return { id: changedPoly.id, latlngs: changedPoly.latlngs };
                    }
                    return polygon;
                });
            });
        });
    };

    console.log(polygons);

    return (
        <MapContainer style={{ height: "100%" }} center={[52.1, 5.1]} zoom={9}>
            <FeatureGroup>
                <EditControl
                    position="topright"
                    onEdited={(e) => onEdited(e.layers)}
                    draw={{ marker: false, circlemarker: false, polyline: false, rectangle: false, circle: false }}
                />

                {polygons?.map((polygon) => {
                    return (
                        <Polygon
                            key={polygon.id}
                            id={polygon.id}
                            positions={polygon.latlngs}
                            pathOptions={{ color: polygon.id === 1 ? "black" : "red" }}
                        />
                    );
                })}
            </FeatureGroup>

            <TileLayer url="" />
        </MapContainer>
    );
}

解决方案

问题根源在于多次异步调用setPolygons导致状态更新不一致,以及Polygon组件的id属性传递方式错误,编辑时无法正确匹配多边形。以下是修复后的代码及说明:

修复后完整代码

import { useState } from "react";
import { MapContainer, TileLayer, FeatureGroup, Polygon } from "react-leaflet";
import { EditControl } from "react-leaflet-draw";
import "leaflet-draw/dist/leaflet.draw.css";

export default function Zones() {
    const _polygon1 = {
        id: 1,
        latlngs: [
            [51.515, 5.09],
            [52.52, 5.1],
            [51.52, 6.12],
        ],
    };
    const _polygon2 = {
        id: 2,
        latlngs: [
            [52, 6.09],
            [52.52, 6.1],
            [52.52, 7.12],
        ],
    };

    const [polygons, setPolygons] = useState([_polygon1, _polygon2]);

    const onEdited = (layers) => {
        // 提取所有修改后的多边形数据
        const changedPolys = Object.values(layers._layers).map((layer) => {
            const latlngs = layer._latlngs[0].map((latlng) => [latlng.lat, latlng.lng]);
            return { 
                id: layer.options.pathOptions.id, 
                latlngs: [...latlngs] // 生成新数组,确保引用更新
            };
        });

        // 一次性更新所有多边形状态,避免多次异步更新冲突
        setPolygons(prevPolygons => {
            return prevPolygons.map(polygon => {
                const matched = changedPolys.find(p => p.id === polygon.id);
                return matched ? { ...matched } : polygon;
            });
        });
    };

    console.log(polygons);

    return (
        <MapContainer style={{ height: "100vh" }} center={[52.1, 5.1]} zoom={9}>
            <FeatureGroup>
                <EditControl
                    position="topright"
                    onEdited={(e) => onEdited(e.layers)}
                    draw={{ marker: false, circlemarker: false, polyline: false, rectangle: false, circle: false }}
                />

                {polygons?.map((polygon) => (
                    <Polygon
                        key={polygon.id}
                        positions={polygon.latlngs}
                        pathOptions={{ 
                            color: polygon.id === 1 ? "black" : "red",
                            id: polygon.id // 将id放在pathOptions中,编辑时能正确获取
                        }}
                    />
                ))}
            </FeatureGroup>

            <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
        </MapContainer>
    );
}

关键修改点

  1. 一次性更新状态:将原有的forEach循环调用setPolygons改为一次性函数式更新,确保基于最新状态修改,避免异步更新导致的状态不一致。
  2. 正确传递id属性:Polygon组件没有id这个原生props,需要将id放在pathOptions中,编辑回调里才能正确获取到多边形的id。
  3. 强制引用更新:对latlngs数组和多边形对象使用扩展运算符生成新引用,确保React能检测到状态变化并重新渲染组件。
  4. 修复TileLayer地址:补充了OpenStreetMap的默认瓦片地址,保证地图正常加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:01:08