如何在react-google-maps中添加自定义功能按钮
现有实现存在的问题
- 触发时机错误:你当前使用
onTilesLoaded事件绑定逻辑,该事件会在每次地图瓦片加载完成时触发(比如用户拖动、缩放地图都会触发),会导致重复渲染CustomControl、重复向地图控制项数组插入元素,最终右上角会出现多个重复按钮。 - 缺少卸载清理逻辑:地图组件卸载时,你通过
ReactDOM.render渲染的自定义按钮组件没有被正确销毁,会产生内存泄漏。 - 缺少边界判断:直接调用
window.google相关属性,若SDK加载异常会直接抛出报错。 - 无法响应Props更新:如果后续
CustomControl的回调或者其他属性发生变化,现有写法无法同步更新按钮的行为逻辑。
更规范的实现方案
适配现有类组件写法的修改方案
首先调整触发时机为onLoad(该事件仅在地图实例首次初始化完成时触发一次),增加实例缓存和卸载清理逻辑:
- 首先在类组件构造函数中新增实例属性缓存元素和地图实例:
constructor(props) { super(props); this.controlBtnDom = null; this.mapInstance = null; // 原有state逻辑不变 this.state = { progress: [] } }
- 修改加载回调逻辑:
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); } };
- 新增组件卸载清理逻辑:
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; } }
- 修改地图组件的事件绑定:
<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
相关产品推荐
相关产品推荐

