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

如何在react-google-maps中添加自定义功能按钮

现有实现存在的问题
  • 触发时机错误:你当前使用onTilesLoaded事件绑定逻辑,该事件会在每次地图瓦片加载完成时触发(比如用户拖动、缩放地图都会触发),会导致重复渲染CustomControl、重复向地图控制项数组插入元素,最终右上角会出现多个重复按钮。
  • 缺少卸载清理逻辑:地图组件卸载时,你通过ReactDOM.render渲染的自定义按钮组件没有被正确销毁,会产生内存泄漏。
  • 缺少边界判断:直接调用window.google相关属性,若SDK加载异常会直接抛出报错。
  • 无法响应Props更新:如果后续CustomControl的回调或者其他属性发生变化,现有写法无法同步更新按钮的行为逻辑。
更规范的实现方案

适配现有类组件写法的修改方案

首先调整触发时机为onLoad(该事件仅在地图实例首次初始化完成时触发一次),增加实例缓存和卸载清理逻辑:

  1. 首先在类组件构造函数中新增实例属性缓存元素和地图实例:
constructor(props) {
  super(props);
  this.controlBtnDom = null;
  this.mapInstance = null;
  // 原有state逻辑不变
  this.state = { progress: [] }
}
  1. 修改加载回调逻辑:
const handleOnLoad = (map) => {
  this.mapInstance = map;
  // 避免重复创建按钮
  if (this.controlBtnDom) return;
  this.controlBtnDom = document.createElement('div');
  ReactDOM.render(<CustomControl onClick={() => console.log('Hi I\'m Here')} />, this.controlBtnDom);
  // 增加边界判断,避免SDK加载异常报错
  if (window.google?.maps?.ControlPosition) {
    map.controls[window.google.maps.ControlPosition.TOP_RIGHT].push(this.controlBtnDom);
  }
};
  1. 新增组件卸载清理逻辑:
componentWillUnmount() {
  // 销毁自定义按钮组件,释放内存
  if (this.controlBtnDom) {
    ReactDOM.unmountComponentAtNode(this.controlBtnDom);
    this.controlBtnDom = null;
  }
  // 移除地图控制项中的按钮元素
  if (this.mapInstance && window.google?.maps?.ControlPosition) {
    const controlList = this.mapInstance.controls[window.google.maps.ControlPosition.TOP_RIGHT];
    const btnIndex = controlList.getArray().findIndex(item => item === this.controlBtnDom);
    if (btnIndex > -1) controlList.removeAt(btnIndex);
    this.mapInstance = null;
  }
}
  1. 修改地图组件的事件绑定:
<GoogleMap
  defaultZoom={16}
  defaultCenter={{ lat: this.props.latVal, lng: this.props.longVal}}
  {/* 将原有的onTilesLoaded替换为onLoad */}
  onLoad={handleOnLoad}
>
  {/* 原有Marker、Polyline、Circle逻辑保持不变 */}
  <Marker 
    position={this.state.progress[this.state.progress.length - 1]}
    icon={{
      url: 'https://images.vexels.com/media/users/3/154573/isolated/preview/bd08e000a449288c914d851cb9dae110-hatchback-car-top-view-silhouette-by-vexels.png',
      scaledSize: new window.google.maps.Size(50, 50),
      anchor: { x: 10, y: 10 }
    }}
  />
  <Polyline 
    path={this.state.progress} 
    options={{ strokeColor: "#FF0000" }} 
  />
  <Circle 
    defaultCenter={{lat: this.props.latVal, lng: this.props.longVal}} 
    radius={parseInt(this.props.geofence)}
    options={{strokeColor: "#ff0000"}}
  />
</GoogleMap>

新版依赖包的更简洁写法

如果你使用的是目前仍在维护的@react-google-maps/api(原react-google-maps旧版已停止维护),可以直接使用官方提供的Control组件,不需要手动操作DOM:

import { GoogleMap, Control, ControlPosition } from '@react-google-maps/api';

<GoogleMap
  defaultZoom={16}
  defaultCenter={{ lat: this.props.latVal, lng: this.props.longVal}}
>
  <Control position={ControlPosition.TOP_RIGHT}>
    <CustomControl onClick={() => console.log('Hi I\'m Here')} />
  </Control>
  {/* 其他子组件保持不变 */}
</GoogleMap>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 11:36:04