React组件结合Google Maps API与@ubilabs Hooks报'google未定义'错误排查
错误成因及解决方案
错误成因
- ESLint静态检查未识别全局变量:Google Maps脚本加载后会在
window上挂载google全局对象,但ESLint默认不知道这个变量的存在,触发no-undef规则报错。 - 脚本加载逻辑重复冲突:你已经通过
GoogleMapsProvider配置了Google Maps脚本的自动加载,却又在组件内手动实现了脚本加载逻辑,不仅重复加载资源,还可能导致google变量初始化时机不一致。 - 依赖判断逻辑冗余:当前用
isGoogleMapsLoaded状态判断脚本加载,但@ubilabs/google-maps-react-hooks提供的useGoogleMapHook返回的map对象,本身就可以作为Google Maps加载完成的标志,额外的状态判断反而容易出问题。
解决方案
1. 消除ESLint的no-undef错误
有两种方式可选:
- 单文件声明全局变量:在组件文件顶部添加注释,告诉ESLint
google是合法的全局变量:/* 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
相关产品推荐
相关产品推荐

