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

google-map-react中useRef调用fitBounds报非函数错误

google-map-react 实现标记点自动适配边界方案

报错原因

通过useRef绑定组件拿到的mapRef.current是google-map-react封装的React组件实例,并非Google Maps JS API提供的原生地图对象,这个封装实例没有挂载fitBounds方法,直接调用就会抛出TypeError: mapRef.current.fitBounds is not a function错误。


可行实现方案

方案1:使用组件内置bounds属性(最简便)

GoogleMapReact组件原生支持bounds属性,只需要计算出所有标记点的边界坐标,按格式传入这个属性,组件会自动完成中心点计算、缩放级别调整,完全不需要手动调用API:

  • 遍历所有标记点,找出纬度最大值、纬度最小值、经度最大值、经度最小值
  • 组装成bounds对象:{ ne: { lat: 最大纬度, lng: 最大经度 }, sw: { lat: 最小纬度, lng: 最小经度 } }
  • 把这个对象传给GoogleMapReact的bounds属性即可,不需要额外绑定ref、写手动调用逻辑

方案2:拿到原生地图实例调用原生fitBounds

如果需要手动触发适配(比如点击按钮才适配、标记点动态加载后触发),可以通过组件提供的onGoogleApiLoaded回调拿到原生地图实例,再调用原生API的fitBounds方法:

  • 新增ref存储原生地图实例,不要直接把ref绑在组件上拿包装实例
  • 给GoogleMapReact传入onGoogleApiLoaded回调,回调触发时把参数里的原生map对象存到ref中
  • 需要适配时,遍历所有标记点生成LatLngBounds对象,调用原生map的fitBounds方法即可

修正后的可运行代码示例

import GoogleMapReact from "google-map-react";
import { Place } from "@material-ui/icons";
import { useRef, useMemo, useState } from "react";

const Page = () => {
  // 存储原生Google地图实例,不是React组件实例
  const nativeMapRef = useRef(null);
  // 示例标记点数据,替换成实际业务数据源即可
  const [currentSearchData, setCurrentSearchData] = useState([
    { latitude: 38.103, longitude: -121.572, name: "点位1" },
    { latitude: 38.12, longitude: -121.55, name: "点位2" },
    { latitude: 38.09, longitude: -121.59, name: "点位3" },
  ]);
  const [view, setView] = useState("recherche");
  const defaultCenter = { lat: 38.103, lng: -121.572 };

  const MarkerPlace = (props) => {
    return (
      <div>
        <Place fontSize={"large"}></Place>
        <p>{props.name}</p>
      </div>
    )
  }

  // 自动计算bounds(方案1直接传这个值给组件的bounds属性即可)
  const mapBounds = useMemo(() => {
    if (!currentSearchData?.length) return null;
    let minLat = Infinity, maxLat = -Infinity, minLng = Infinity, maxLng = -Infinity;
    currentSearchData.forEach(item => {
      minLat = Math.min(minLat, item.latitude);
      maxLat = Math.max(maxLat, item.latitude);
      minLng = Math.min(minLng, item.longitude);
      maxLng = Math.max(maxLng, item.longitude);
    });
    // 预留少量边距,避免标记点贴到地图边缘被控件遮挡
    const latPadding = (maxLat - minLat) * 0.1 || 0.01;
    const lngPadding = (maxLng - minLng) * 0.1 || 0.01;
    return {
      ne: { lat: maxLat + latPadding, lng: maxLng + lngPadding },
      sw: { lat: minLat - latPadding, lng: minLng - lngPadding }
    }
  }, [currentSearchData]);

  // 手动触发fitBounds(方案2逻辑)
  const handleFitBounds = () => {
    if (!nativeMapRef.current || !window.google?.maps) return;
    const bounds = new window.google.maps.LatLngBounds();
    currentSearchData.forEach(item => {
      bounds.extend(new window.google.maps.LatLng(item.latitude, item.longitude));
    });
    nativeMapRef.current.fitBounds(bounds);
  }

  return (
    <div style={{ height: "100vh", width: "100%" }}>
      <GoogleMapReact
        bootstrapURLKeys={{ key: "替换为实际申请的地图Key" }}
        defaultCenter={defaultCenter}
        defaultZoom={13}
        // 方案1:直接传bounds属性,加载即自动适配
        bounds={mapBounds}
        // 回调中拿到原生地图实例存储
        onGoogleApiLoaded={({ map }) => {
          nativeMapRef.current = map;
        }}
        options={{ fullscreenControl: false }}
      >
        {view === "recherche" && currentSearchData.map((activity, index) => (
          <MarkerPlace
            key={index}
            lat={activity.latitude}
            lng={activity.longitude}
            name={activity.name}
          />
        ))}
      </GoogleMapReact>
      <button onClick={handleFitBounds} style={{ position: "absolute", top: 20, left: 20, zIndex: 10 }}>
        适配所有点位
      </button>
    </div>
  )
}

export default Page;

注意事项

  • 不要把ref直接挂在GoogleMapReact组件上调用原生API,拿到的封装实例只暴露了极少部分内部方法,没有原生地图的完整能力
  • 计算bounds的时候建议加少量边距,避免最边缘的标记点被地图缩放控件、版权信息遮挡
  • 如果标记点是异步加载的,等数据加载完成后再更新bounds或者触发fitBounds即可,不需要手动编写复杂的缩放级别计算逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 01:30:47