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

React页面中Google Map折线切换焦点后重置问题求助

问题描述

React页面分为上下两部分:上半部分是表单,下半部分是Google Map组件。在地图中添加Polyline后,左键点击添加点、右键点击删除点或拖拽折线时,路径更新正常;但操作表单区域的输入框/按钮后,再尝试添加/删除折线点,会创建新折线(删除操作因无点可删失效)。

现有核心代码如下:

事件处理与地图渲染代码

const addLatLng = (event) => {
  const path = poly.getPath();
  path.push(event.latLng);
}

const removeVertex = (vertex) => {
  let path = poly.getPath();
  path.removeAt(vertex)
}

// eslint-disable-next-line no-undef
google.maps.event.addListener(poly, 'rightclick', function (event) {
  if (event.vertex === undefined) {
    return;
  } else {
    removeVertex(event.vertex)
  }
})
<div style={{ height: '100vh' }}>
  <GoogleMap
    center={center}
    zoom={3}
    onLoad={(map) => setMap(map)}
    mapContainerStyle={{ width: '100%', height: '100%' }}
    onClick={(event) => { !showInputForLink && addLatLng(event) }}
  >
  </GoogleMap>
</div>

地图与折线声明代码

const { isLoaded } = useJsApiLoader({
  googleMapsApiKey: ct.MAPS_API_KEY,
  libraries: ['drawing, places']
})
// eslint-disable-next-line no-undef
const [map, setMap] = useState(/** @type google.maps.Map */(null))  

const poly = new google.maps.Polyline({
  strokeColor: '#160BB9',
  strokeOpacity: 1.0,
  strokeWeight: 3,
  editable: true,
});

poly.setMap(map)
问题原因

每次操作表单触发组件重新渲染时,const poly = new google.maps.Polyline(...)都会重新执行,创建全新的Polyline实例,之前的实例和路径数据完全丢失。同时,初始渲染时map为null,poly.setMap(map)不会生效;地图加载后组件重渲染,又会重复创建新实例并挂载到地图上,导致多条折线共存,旧实例的事件监听失效。

解决方案

1. 用useRef持久化Polyline实例

useRef可以在组件多次渲染间保存同一个实例,不会随重渲染重新创建:

// 替换原有的poly声明
const polyRef = useRef(null);

2. 在地图加载后初始化折线与事件监听

仅当地图加载完成时,才创建并挂载Polyline,避免map为null的情况,同时把事件监听绑定到持久化的实例上:

<GoogleMap
  center={center}
  zoom={3}
  onLoad={(mapInstance) => {
    setMap(mapInstance);
    // 初始化折线并保存到ref
    const poly = new google.maps.Polyline({
      strokeColor: '#160BB9',
      strokeOpacity: 1.0,
      strokeWeight: 3,
      editable: true,
    });
    poly.setMap(mapInstance);
    polyRef.current = poly;

    // 绑定右键删除事件
    google.maps.event.addListener(poly, 'rightclick', function (event) {
      if (event.vertex === undefined) return;
      removeVertex(event.vertex);
    });
  }}
  mapContainerStyle={{ width: '100%', height: '100%' }}
  onClick={(event) => { !showInputForLink && addLatLng(event) }}
>
</GoogleMap>

3. 修改事件处理函数,使用ref中的实例

确保操作的是同一个持久化的折线实例:

const addLatLng = (event) => {
  if (!polyRef.current) return; // 避免实例未初始化时操作
  const path = polyRef.current.getPath();
  path.push(event.latLng);
}

const removeVertex = (vertex) => {
  if (!polyRef.current) return;
  const path = polyRef.current.getPath();
  path.removeAt(vertex);
}

4. 组件卸载时清理资源(可选)

避免内存泄漏,卸载时移除折线和事件监听:

useEffect(() => {
  return () => {
    if (polyRef.current) {
      google.maps.event.clearInstanceListeners(polyRef.current);
      polyRef.current.setMap(null);
    }
  };
}, []);
关键说明

不需要替换为地图内声明的Poly组件,核心是让Polyline实例在组件重渲染时保持唯一,通过useRef实现持久化,同时把实例初始化和事件绑定逻辑放到地图加载的回调中,避免重复执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:31:20