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

React中使用Open Layer渲染地图出现重复渲染问题求助

React中OpenLayers地图重复渲染两次的解决办法

在React里用OpenLayers实现地图功能时,出现了地图重复渲染两次的情况,相关代码如下:

MapView组件代码:

export default function MapView() {
  const view = new View({
    center: [0, 0],
    zoom: 2,
  });
  useEffect(() => {
      new Map({
        layers: [
            new TileLayer({source: new OSM()}),
        ],
        view: view,
        target:'map',
      })
  },[])

  return (
    <>
      <div id="map" style={{width:'100%',height:'400px'}}></div>
    </>   
  )
}

父组件App代码:

function App() {
  return (
    <div>
      <MapView />
    </div>
  );
}

问题根源

  1. 开发环境下React的StrictMode会强制组件执行两次渲染,连useEffect钩子也会触发两遍,这就导致OpenLayers的Map实例被创建了两次,且都挂载到同一个#map容器中,最终出现重复地图。
  2. 另外,View实例是在组件函数体中创建的,每次组件渲染都会生成新的View对象,虽然不会直接引发重复渲染,但属于不必要的性能损耗。

解决办法

通过给useEffect添加清理函数、缓存View实例、用ref跟踪Map对象,确保只创建一次Map实例:

修改后的代码:

import { useEffect, useMemo, useRef } from 'react';
import { Map, View, TileLayer } from 'ol';
import OSM from 'ol/source/OSM';

export default function MapView() {
  // 用useMemo缓存View实例,仅初始化一次
  const view = useMemo(() => new View({
    center: [0, 0],
    zoom: 2,
  }), []);

  // 用ref存储Map实例,避免重复创建
  const mapRef = useRef(null);

  useEffect(() => {
    // 仅当Map实例不存在时才创建
    if (!mapRef.current) {
      mapRef.current = new Map({
        layers: [
          new TileLayer({ source: new OSM() }),
        ],
        view: view,
        target: 'map',
      });
    }

    // 组件卸载时销毁Map实例,清理资源
    return () => {
      if (mapRef.current) {
        mapRef.current.dispose();
        mapRef.current = null;
      }
    };
  }, [view]);

  return (
    <div id="map" style={{ width: '100%', height: '400px' }}></div>
  );
}

额外优化建议

避免使用固定id作为Map的target,改用React的ref绑定DOM元素,更符合组件化思想:

// 调整后的核心代码片段
const mapContainerRef = useRef(null);

useEffect(() => {
  if (!mapRef.current && mapContainerRef.current) {
    mapRef.current = new Map({
      layers: [new TileLayer({ source: new OSM() })],
      view: view,
      target: mapContainerRef.current, // 使用ref指向的DOM元素
    });
  }

  return () => {
    if (mapRef.current) {
      mapRef.current.dispose();
      mapRef.current = null;
    }
  };
}, [view]);

return (
  <div ref={mapContainerRef} style={{ width: '100%', height: '400px' }}></div>
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 11:30:52