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

React+OpenLayers绘制完成后Vector Layer在地图上消失问题求助

OpenLayers Draw交互绘制完成后内容消失的修复方案

问题原因

  1. 未移除旧的Draw交互:每次切换绘制类型时,新创建的Draw交互被添加到地图,但旧的交互未被移除,多个Draw交互同时存在会导致逻辑冲突,引发绘制完成后Feature被意外移除。
  2. None类型未处理交互移除:选择清除(None)时,没有停止当前的Draw交互,残留的交互会干扰后续操作。
  3. 状态管理不够稳妥:使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 22:40:23