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> ); }
关键修改点
- 一次性更新状态:将原有的
forEach循环调用setPolygons改为一次性函数式更新,确保基于最新状态修改,避免异步更新导致的状态不一致。 - 正确传递id属性:
Polygon组件没有id这个原生props,需要将id放在pathOptions中,编辑回调里才能正确获取到多边形的id。 - 强制引用更新:对
latlngs数组和多边形对象使用扩展运算符生成新引用,确保React能检测到状态变化并重新渲染组件。 - 修复TileLayer地址:补充了OpenStreetMap的默认瓦片地址,保证地图正常加载。
内容的提问来源于stack exchange,提问作者frankm
相关产品推荐
相关产品推荐

