React Google Map点击Marker后弹出两个InfoWindow的问题排查求助
解决点击Marker出现多个InfoWindow的问题
嘿,我仔细看了你的代码,终于找到问题的根源了!咱们一步步拆解:
问题核心原因
- 错误的
bind使用:在MyMapComponent的map循环里,你用了props.onMarkerClick.bind(this, location),但这里的this在函数组件环境下是undefined,这会导致绑定的回调函数出现异常,可能触发多次点击事件,进而让state重复更新,渲染多个InfoWindow。 - 不稳定的Marker Key:你用
nanoid()作为Marker的key,这意味着每次组件render时,Marker都会被重新创建(因为key每次都不一样),这种频繁的挂载/卸载很容易引发奇怪的事件触发问题,包括重复显示InfoWindow。 - 调试模式的特殊性:React调试模式会严格检查组件渲染流程,可能会抑制一些重复触发的异常,所以你在调试时看不到问题,但生产环境就暴露了。
修复方案
咱们针对性修改这几个点:
1. 替换不稳定的Marker Key
把Marker的key改成基于location坐标的稳定字符串,这样只有当location真正变化时,Marker才会重新渲染:
<Marker key={`${location.lat}-${location.lng}`} position={location} onClick={() => props.onMarkerClick(location)} />
2. 正确传递点击回调
用箭头函数直接传递location参数,代替错误的bind操作,确保回调函数正确绑定到Test组件的上下文:
// 直接在onClick中写箭头函数,避免bind的问题 onClick={() => props.onMarkerClick(location)}
3. 优化InfoWindow渲染逻辑
增加activeMarker存在的判断,避免当activeMarker为null时还尝试渲染InfoWindow,减少不必要的渲染触发:
修改后的完整代码
import { GoogleMap, Marker, withGoogleMap, withScriptjs, InfoWindow } from "react-google-maps"; import React, { Component } from 'react' const API_KEY = 'INSERT_API_KEY' const MyMapComponent = withScriptjs(withGoogleMap((props) => ( <GoogleMap defaultZoom={8} defaultCenter={{ lat: -33.897, lng: 151.144 }}> {props.locs.map((location) => ( <Marker key={`${location.lat}-${location.lng}`} position={location} onClick={() => props.onMarkerClick(location)} /> ))} {props.showingInfoWindow && props.activeMarker && ( <InfoWindow position={props.activeMarker} onCloseClick={props.markerInfoClose} > <h1>Details</h1> </InfoWindow> )} </GoogleMap> ))); export default class Test extends Component { constructor(props) { super(props); this.state = { locations: [{ lat: -33.865143, lng: 151.2 }], showingInfoWindow: false, activeMarker: null, }; } onMarkerClick = (location) => { this.setState({ activeMarker: location, showingInfoWindow: true }); } onClose = () => { this.setState({ activeMarker: null, showingInfoWindow: false }); }; render() { console.log(this.state.activeMarker) return ( <div> <MyMapComponent locs={this.state.locations} onMarkerClick={this.onMarkerClick} showingInfoWindow={this.state.showingInfoWindow} activeMarker={this.state.activeMarker} markerInfoClose={this.onClose} containerElement={<div style={{ height: `1000px`, width: '1000px' }} />} mapElement={<div style={{ height: `100%` }} />} loadingElement={<div style={{ height: `100%` }} />} googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${API_KEY}`} /> </div> ) } }
额外说明
- 我去掉了
nanoid依赖,用坐标拼接的key已经足够稳定,除非你的locations有重复坐标的情况,那时再考虑添加唯一id即可。 - 调试模式下React会做两次渲染检查,所以有时候会掩盖这类重复触发的问题,这也是你调试时正常的原因。
内容的提问来源于stack exchange,提问作者FrozenGiraffeLiang
相关产品推荐
相关产品推荐

