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

React组件结合Google Maps API与@ubilabs Hooks报'google未定义'错误排查

错误成因及解决方案

错误成因

  1. ESLint静态检查未识别全局变量:Google Maps脚本加载后会在window上挂载google全局对象,但ESLint默认不知道这个变量的存在,触发no-undef规则报错。
  2. 脚本加载逻辑重复冲突:你已经通过GoogleMapsProvider配置了Google Maps脚本的自动加载,却又在组件内手动实现了脚本加载逻辑,不仅重复加载资源,还可能导致google变量初始化时机不一致。
  3. 依赖判断逻辑冗余:当前用isGoogleMapsLoaded状态判断脚本加载,但@ubilabs/google-maps-react-hooks提供的useGoogleMap Hook返回的map对象,本身就可以作为Google Maps加载完成的标志,额外的状态判断反而容易出问题。

解决方案

1. 消除ESLint的no-undef错误

有两种方式可选:

  • 单文件声明全局变量:在组件文件顶部添加注释,告诉ESLintgoogle是合法的全局变量:
    /* global google */
    import React, { useEffect, useState, useCallback } from "react";
    // ... 其他代码
    
  • 项目全局配置ESLint:在项目根目录的.eslintrc.js中添加全局变量声明,所有文件都能生效:
    module.exports = {
      // ... 其他ESLint配置
      globals: {
        google: "readonly"
      }
    };
    

2. 移除手动脚本加载逻辑,依赖Provider自动加载

删掉组件内这段手动加载脚本的useEffect:

// 完全删除这段代码
useEffect(() => {
  const loadGoogleMapsScript = () => {
    const script = document.createElement("script");
    script.src = `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLEMAPS_APIKEY}&libraries=places`;
    script.async = true;
    script.defer = true;

    script.onload = () => {
      setIsGoogleMapsLoaded(true);
    };

    document.head.appendChild(script);
  };

  if (!isGoogleMapsLoaded) {
    loadGoogleMapsScript();
  }
}, [isGoogleMapsLoaded]);

同时删除isGoogleMapsLoaded相关的状态声明和依赖逻辑,改用useGoogleMap返回的map对象作为加载完成的标志:

// 删除这行状态声明
// const [isGoogleMapsLoaded, setIsGoogleMapsLoaded] = useState(false);

// 替换原有的触发calculateRouteAndETA的useEffect
useEffect(() => {
  if (map && studentAddresses.length > 0 && selectedTime) {
    calculateRouteAndETA();
  }
}, [map, studentAddresses, selectedTime, calculateRouteAndETA]);

3. 修复ETA计算的逻辑错误(额外优化)

你当前的ETA计算是用单个路段的时间乘以索引,这不符合实际路线的时间累加逻辑。正确的做法是从routes[0].legs数组中逐个累加每个路段的交通时间:

findAndRenderRoute(request)
  .then((result) => {
    const route = result.routes[0];
    let accumulatedTime = 0;
    const updatedStudentETAs = studentAddresses.map((address, index) => {
      const leg = route.legs[index];
      accumulatedTime += leg.duration_in_traffic.value;
      return {
        address,
        eta: accumulatedTime
      };
    });
    setStudentETAs(updatedStudentETAs);
  })
  .catch((errorStatus) => {
    console.error(errorStatus);
  });

最终修改后的核心代码片段

/* global google */
import React, { useEffect, useState, useCallback } from "react";
import { useDirectionsService, useGoogleMap } from "@ubilabs/google-maps-react-hooks";

function GoogleMapsDirections({ students }) {
  const map = useGoogleMap();
  const [selectedTime, setSelectedTime] = useState("");
  const departureAddress = "2440 Main St, Vancouver, BC V5T 3E2";
  const [studentAddresses, setStudentAddresses] = useState([]);
  const [studentETAs, setStudentETAs] = useState([]);
  
  const { findAndRenderRoute, directionsRenderer } = useDirectionsService({
    renderOnMap: true,
    renderOptions: {
      suppressMarkers: true,
      polylineOptions: { strokeColor: "#FB2576", strokeWeight: 4 },
    },
  });

  // ... 其他原有useEffect(获取学生地址的逻辑保留)

  const calculateRouteAndETA = useCallback(() => {
    if (!studentAddresses.length || !selectedTime) return;

    const request = {
      travelMode: google.maps.TravelMode.DRIVING,
      origin: departureAddress,
      destination: studentAddresses.at(-1),
      waypoints: studentAddresses.slice(0, -1).map(address => ({
        location: address,
        stopover: true,
      })),
      drivingOptions: {
        departureTime: new Date(selectedTime),
        trafficModel: google.maps.TrafficModel.BEST_GUESS,
      },
    };

    findAndRenderRoute(request)
      .then((result) => {
        const route = result.routes[0];
        let accumulatedTime = 0;
        const updatedStudentETAs = studentAddresses.map((address, index) => {
          const leg = route.legs[index];
          accumulatedTime += leg.duration_in_traffic.value;
          return { address, eta: accumulatedTime };
        });
        setStudentETAs(updatedStudentETAs);
      })
      .catch(console.error);
  }, [studentAddresses, selectedTime, departureAddress, findAndRenderRoute]);

  // 新的触发逻辑,依赖map对象存在
  useEffect(() => {
    if (map && studentAddresses.length > 0 && selectedTime) {
      calculateRouteAndETA();
    }
  }, [map, studentAddresses, selectedTime, calculateRouteAndETA]);

  // ... 清理逻辑和返回JSX保留
}

export default GoogleMapsDirections;

内容的提问来源于stack exchange,提问作者Leonardo Picchi Lpdancona

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 14:02:02