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

如何在react-google-maps挂载后为地图/聚合器增删标记?

在react-google-maps中动态添加/移除MarkerClusterer标记的正确方式

我之前也踩过这个坑,那个Uncaught TypeError: Cannot read property '__SECRET_MARKER_CLUSTERER_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined错误,本质是因为你搞错了react-google-maps组件的工作逻辑——它是受控组件,不能直接操作底层Google Maps原生实例来修改标记,必须通过React的状态管理来同步标记列表。

为什么你的原有方法会失败?

react-google-maps封装了MarkerClusterer的底层实例,组件内部依赖这个“私有”属性来维护React组件和原生地图实例的状态同步。你直接调用原生的addMarker方法或者创建原生Marker挂载到地图上,完全绕过了React的生命周期,导致组件状态和底层实例不一致,最终触发这个错误。

正确解决方案:用React状态管理标记列表

MarkerClusterer是通过子组件<Marker>来管理标记的,所以你只需要维护一个标记数据的数组,通过修改这个数组(更新状态)让React自动重新渲染MarkerClusterer和内部的标记,底层的聚合逻辑会自动处理。

具体步骤

  1. 用状态维护标记数据
    用useState(函数组件)或者this.state(类组件)来存储标记数组,比如在父组件中初始化:

    const [markers, setMarkers] = useState(props.hotels.results.map((item, index) => ({
      id: index, // 给每个标记设置唯一ID,方便后续操作
      lat: parseFloat(item.latitude),
      lng: parseFloat(item.longitude),
      title: item.name // 可选:标记的标题
    })));
    
  2. 调整Map组件,接收标记props
    修改你的高阶组件,让它接收markers数组和点击回调:

    const MapWithAMarkerClusterer = compose(
      withProps({
        googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=AIzaSyATVkXuYRZCkB73ZsPEJisDy74GnVusIJw",
        loadingElement: <div style={{ height: `100%` }} />,
        containerElement: <div className="mapContainer" />,
        mapElement: <div style={{ height: `100%` }} />,
      }),
      withScriptjs,
      withGoogleMap
    )(props => (
      <GoogleMap defaultZoom={3} defaultCenter={{ lat: 25.0391667, lng: 121.525 }}>
        <MarkerClusterer
          onClick={props.onClusterClick}
          averageCenter
          enableRetinaIcons
          gridSize={60}
        >
          {props.markers.map(marker => (
            <Marker
              key={marker.id}
              position={{ lat: marker.lat, lng: marker.lng }}
              title={marker.title}
            />
          ))}
        </MarkerClusterer>
      </GoogleMap>
    ));
    
  3. 动态添加标记:更新状态数组
    在点击按钮或MarkerClusterer的点击事件中,不要操作原生实例,而是更新标记数组的状态:

    const handleClusterClick = () => {
      // 定义新标记的数据
      const newMarker = {
        id: Date.now(), // 用时间戳作为唯一ID
        lat: 56.565123,
        lng: 9.030908,
        title: 'Hello World!'
      };
      // 追加新标记到数组,更新状态
      setMarkers(prevMarkers => [...prevMarkers, newMarker]);
    };
    
  4. 动态移除标记:过滤状态数组
    如果需要移除某个标记,只需过滤掉对应ID的项即可:

    const removeMarker = (markerId) => {
      setMarkers(prevMarkers => prevMarkers.filter(marker => marker.id !== markerId));
    };
    

完整修正示例(函数组件版本)

import React, { useState } from 'react';
import { compose, withProps, withScriptjs, withGoogleMap, GoogleMap, Marker, MarkerClusterer } from 'react-google-maps';

const MapWithAMarkerClusterer = compose(
  withProps({
    googleMapURL: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=AIzaSyATVkXuYRZCkB73ZsPEJisDy74GnVusIJw",
    loadingElement: <div style={{ height: `100%` }} />,
    containerElement: <div style={{ height: '80vh' }} />,
    mapElement: <div style={{ height: `100%` }} />,
  }),
  withScriptjs,
  withGoogleMap
)((props) => (
  <GoogleMap defaultZoom={3} defaultCenter={{ lat: 25.0391667, lng: 121.525 }}>
    <MarkerClusterer
      onClick={props.onClusterClick}
      averageCenter
      enableRetinaIcons
      gridSize={60}
    >
      {props.markers.map((marker) => (
        <Marker
          key={marker.id}
          position={{ lat: marker.lat, lng: marker.lng }}
          title={marker.title}
        />
      ))}
    </MarkerClusterer>
  </GoogleMap>
));

export default function HotelMap(props) {
  // 初始化酒店标记列表
  const [markers, setMarkers] = useState(props.hotels.results.map((item, index) => ({
    id: index,
    lat: parseFloat(item.latitude),
    lng: parseFloat(item.longitude),
    title: item.name
  })));

  const handleClusterClick = () => {
    // 点击聚合器时添加新标记
    const newMarker = {
      id: Date.now(),
      lat: 56.565123,
      lng: 9.030908,
      title: 'Hello World!'
    };
    setMarkers(prev => [...prev, newMarker]);
  };

  return (
    <div>
      <button onClick={handleClusterClick}>点击添加测试标记</button>
      <MapWithAMarkerClusterer markers={markers} onClusterClick={handleClusterClick} />
    </div>
  );
}

关键注意事项

  • 永远不要直接操作react-google-maps组件的refs来调用原生方法,必须通过React状态同步组件和底层实例。
  • 给每个<Marker>设置唯一的key,避免React渲染时出现重复或错误。
  • 标记数据最好包含唯一ID,方便后续的移除、修改操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:03:39