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

React Google Map点击Marker后弹出两个InfoWindow的问题排查求助

解决点击Marker出现多个InfoWindow的问题

嘿,我仔细看了你的代码,终于找到问题的根源了!咱们一步步拆解:

问题核心原因

  1. 错误的bind使用:在MyMapComponent的map循环里,你用了props.onMarkerClick.bind(this, location),但这里的this在函数组件环境下是undefined,这会导致绑定的回调函数出现异常,可能触发多次点击事件,进而让state重复更新,渲染多个InfoWindow。
  2. 不稳定的Marker Key:你用nanoid()作为Marker的key,这意味着每次组件render时,Marker都会被重新创建(因为key每次都不一样),这种频繁的挂载/卸载很容易引发奇怪的事件触发问题,包括重复显示InfoWindow。
  3. 调试模式的特殊性: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:42:48