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

React Google Maps API点击首个标记时map状态为null问题求助

求助:React Google Maps API 点击Marker首次不显示Circle问题

需求说明

在Google地图上显示一组Marker,点击标记时在地图上添加Google Circle。

实际现象

首次点击标记时,圆形不显示;但点击第二个及以后的标记时,圆形能正常显示。

问题排查

通过console.log追踪map状态发现,首次进入markerClicked函数时,map状态值为null,导致无法创建圆形;但地图首次加载时和后续点击标记时,map状态都包含有效的地图实例。

组件代码

import { GoogleMap, MarkerF, useJsApiLoader } from "@react-google-maps/api";
import Box from '@mui/material/Box';
import { useSelector } from 'react-redux'

let mapCircle1 = null

export default function MapPage() {
  // 标记数组存储在REDUX中
  const selectMarkersArray = state => state.markersArray
  const markersArray = useSelector(selectMarkersArray)

  // 存储选中的标记(未选中时为null)
  const [selectedMarker, setSelectedMarker] = useState(null);

  // 谷歌地图配置项
  let center = {
      lat: 43.3318,
      lng: 5.0550
  }
  let zoom = 15
  const containerStyle = {
      width: "100%",
      height: "100%"
  }

  // 谷歌地图加载逻辑
  const { isLoaded } = useJsApiLoader({
      id: 'google-map-script',
      googleMapsApiKey: "MY-GOOGLE-KEY"
  })
  const [map, setMap] = useState(null)
  const onLoad = useCallback(function callback(map) {
    setMap(map)
    console.log('map value in onLoad :')
    console.log(map)
  }, [])
  const onUnmount = useCallback(function callback(map) {
  setMap(null)
  }, [])

  // 标记点击触发的函数
  function markerClicked(props) {
    console.log('map value in markerClicked :')
    console.log(map)

    // 创建圆形配置
    let circleOption1 = {
      fillColor: "#2b32ac ",
      map: map,
      center: {lat:props.marker.spotLatitude, lng:props.marker.spotLongitude},
      radius: props.marker.spotCircleRadius,
    };
    mapCircle1 = new window.google.maps.Circle(circleOption1);

    // 更新选中标记状态
      setSelectedMarker({...props.marker})
    }
    return (isLoaded ? (
      <Box height="80vh" display="flex" flexDirection="column">
        <GoogleMap 
          mapContainerStyle={containerStyle}
          center={center}
          zoom={zoom}                
          onLoad={onLoad}
          onUnmount={onUnmount}
        >
          {markersArray.map((marker, index) => {
            return (
              <MarkerF 
                key={index.toString()} 
                position={{lat:marker.spotLatitude, lng:marker.spotLongitude}}
                onClick={() => markerClicked({marker:marker})}
                >
              </MarkerF>
            )
          })}
        </GoogleMap>
      </Box>
    ) : <></>
  )
};

控制台日志

map value in onLoad :
jj {gm_bindings_: {…}, __gm: hda, gm_accessors_: {…}, mapCapabilities: {…}, renderingType: 'UNINITIALIZED', …}

map value in markerClicked :
null

map value in markerClicked :
jj {gm_bindings_: {…}, __gm: hda, gm_accessors_: {…}, mapCapabilities: {…}, renderingType: 'RASTER', …}

问题原因

首次点击时markerClicked函数捕获的是组件初始渲染时的map状态(值为null),这是函数闭包特性导致的:组件首次渲染时创建的markerClicked函数,会绑定当时的map状态值(null)。虽然之后onLoad更新了map状态,但这个旧的markerClicked函数并没有重新创建,直到组件因setSelectedMarker触发重新渲染,才会生成新的markerClicked函数,此时它捕获的是更新后的有效map实例。

解决方案

方式1:用useCallback包裹markerClicked,依赖map状态

将markerClicked用useCallback包裹,并把map加入依赖数组,这样每次map状态更新时,都会生成新的函数实例,确保能获取到最新的map值:

const markerClicked = useCallback((props) => {
  console.log('map value in markerClicked :')
  console.log(map)

  if (!map) return; // 增加空值判断,避免报错

  let circleOption1 = {
    fillColor: "#2b32ac ",
    map: map,
    center: {lat:props.marker.spotLatitude, lng:props.marker.spotLongitude},
    radius: props.marker.spotCircleRadius,
  };
  mapCircle1 = new window.google.maps.Circle(circleOption1);

  setSelectedMarker({...props.marker})
}, [map])

方式2:通过ref存储map实例

使用useRef替代useState存储map实例,因为ref的更新不会触发组件重新渲染,且能直接获取最新值,避免闭包问题:

// 替换原来的useState为useRef
const mapRef = useRef(null)
const onLoad = useCallback(function callback(map) {
  mapRef.current = map
  console.log('map value in onLoad :')
  console.log(map)
}, [])
const onUnmount = useCallback(function callback(map) {
  mapRef.current = null
}, [])

// 修改markerClicked函数
function markerClicked(props) {
  const map = mapRef.current
  console.log('map value in markerClicked :')
  console.log(map)

  if (!map) return;

  let circleOption1 = {
    fillColor: "#2b32ac ",
    map: map,
    center: {lat:props.marker.spotLatitude, lng:props.marker.spotLongitude},
    radius: props.marker.spotCircleRadius,
  };
  mapCircle1 = new window.google.maps.Circle(circleOption1);

  setSelectedMarker({...props.marker})
}

额外优化建议

全局变量mapCircle1可能导致内存泄漏,建议改用ref存储,在每次创建新Circle前先销毁旧的Circle:

// 用ref存储circle实例
const circleRef = useRef(null)

// 在markerClicked里添加销毁逻辑
if (circleRef.current) {
  circleRef.current.setMap(null)
}
circleRef.current = new window.google.maps.Circle(circleOption1)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 11:35:30