React+OpenLayers绘制完成后Vector Layer在地图上消失问题求助
OpenLayers Draw交互绘制完成后内容消失的修复方案
问题原因
- 未移除旧的Draw交互:每次切换绘制类型时,新创建的Draw交互被添加到地图,但旧的交互未被移除,多个Draw交互同时存在会导致逻辑冲突,引发绘制完成后Feature被意外移除。
- None类型未处理交互移除:选择清除(None)时,没有停止当前的Draw交互,残留的交互会干扰后续操作。
- 状态管理不够稳妥:使用
useState存储VectorSource实例,虽然初始值仅执行一次,但用useRef存储实例更符合OpenLayers这类非React原生对象的管理习惯,避免潜在的状态更新问题。
修复步骤
- 用
useRef存储VectorSource和Draw交互的实例,确保引用稳定。 - 每次切换绘制类型前,移除之前的Draw交互。
- 处理None类型的逻辑,移除当前Draw交互以停止绘制。
- 组件卸载时清理图层和交互,避免内存泄漏。
修改后的完整代码
import React, { useState, useEffect, useRef, useContext } from 'react' import MapContext from '../contexts/MapContext'; import './Measure.css' import { Layer as VectorLayer } from 'ol/layer'; import { Vector as VectorSource } from 'ol/source' import { Draw as OLdraw } from 'ol/interaction' export default function Measure() { const map = useContext(MapContext); const [drawType, setdrawType] = useState('None'); const overlayRef = useRef(); const [toggleOn, setToggleOn] = useState(false); // 用useRef存储source和draw实例,保证引用稳定 const sourceRef = useRef(new VectorSource({ wrapX: false })); const drawRef = useRef(null); useEffect(() => { const drawLayer = new VectorLayer({ source: sourceRef.current, map, zIndex: 10000, visible: true }); map.addLayer(drawLayer); // 组件卸载时移除图层 return () => { map.removeLayer(drawLayer); }; }, [map]) useEffect(() => { // 移除之前的Draw交互 if (drawRef.current) { map.removeInteraction(drawRef.current); drawRef.current = null; } let draw; switch (drawType) { case 'Point': draw = new OLdraw({ type: drawType, stopClick: true, source: sourceRef.current }); break; case 'LineString': draw = new OLdraw({ type: drawType, stopClick: true, source: sourceRef.current }); break; case 'Polygon': draw = new OLdraw({ type: drawType, stopClick: true, source: sourceRef.current }); break; case 'None': // 选择None时直接返回,不创建新交互 return; default: return; } if (draw) { map.addInteraction(draw); drawRef.current = draw; // 可选:监听drawend事件,验证Feature是否正确添加 draw.on('drawend', (e) => { console.log('绘制完成,Feature已添加到Source:', e.feature); }); } // 清理函数:移除当前Draw交互 return () => { if (drawRef.current) { map.removeInteraction(drawRef.current); drawRef.current = null; } }; }, [drawType, map]) const toggleHandle = () => { setToggleOn(prev => !prev); }; const handleDrawType = (e) => { const value = e.target.value; setdrawType(value); } return ( <div className="draw"> <div ref={overlayRef}></div> <div className='measurement'> <div className='toggle' onClick={toggleHandle}> <span><img src='./assets/measure/measure.svg'></img></span> </div> {toggleOn ? <div className='options' onClick={handleDrawType}> <span><img src='./assets/measure/point.svg' value="Point"></img></span> <span><img src='./assets/measure/area.svg' value="LineString"></img></span> <span><img src='./assets/measure/polyline.svg' value="Polygon"></img></span> <span><img src='./assets/measure/trash.svg' value="None"></img></span> </div> : null} </div> </div> ) }
内容的提问来源于stack exchange,提问作者ümit
相关产品推荐
相关产品推荐

