如何在同一NextJS页面使用GoogleMap与Autocomplete?解决API重复加载报错
解决Google Maps API重复加载的问题
问题根源是react-google-autocomplete和@react-google-maps/api各自独立加载了Google Maps API脚本,导致重复引入。解决思路是统一API加载逻辑,让两个组件复用同一套已加载的API。
具体修改步骤:
- 修改Map组件的API加载配置
在useJsApiLoader中添加libraries: ["places"],因为自动补全功能依赖Google Places库,需确保加载的API包含该服务:
// Map组件修改后代码 import { GoogleCoords } from "@/typings"; import { GoogleMap, useJsApiLoader, Marker } from "@react-google-maps/api"; interface Props { center: GoogleCoords; zoom: number; listOfCoordinates: GoogleCoords[]; handleOnRightClick: any; handleOnDragEndMarker: any; } const Map = ({ center, zoom, listOfCoordinates, handleOnRightClick, handleOnDragEndMarker, }: Props) => { const { isLoaded } = useJsApiLoader({ id: "google-map-script", googleMapsApiKey: "API_KEY", // 添加places库,支持自动补全功能 libraries: ["places"] }); return ( <> {isLoaded && ( <GoogleMap mapContainerStyle={{ width: 600, height: 600 }} options={{ streetViewControl: false, mapTypeId: "satellite", }} center={center} zoom={zoom} tilt={0} onRightClick={handleOnRightClick} clickableIcons={false}> {listOfCoordinates.map((point, index) => ( <Marker draggable={true} onDragEnd={(e) => handleOnDragEndMarker(e, index)} key={index} position={point} /> ))} </GoogleMap> )} </> ); }; export default Map;
- 禁用Autocomplete组件的自动API加载
在页面中的Autocomplete组件添加loadScript={false}属性,让它复用Map组件已加载好的Google Maps API,不再自行加载:
// 页面组件修改后代码 import Map from "@/components/Map"; import { grayMid } from "@/theme/colors"; import { GoogleCoords } from "@/typings"; import { LegacyRef, useRef, useState } from "react"; import Autocomplete from "react-google-autocomplete"; const AddGolfCoursePage = () => { const [center, setCenter] = useState<GoogleCoords>({ lat: 0, lng: 0, }); const [zoom, setZoom] = useState(2); const [listOfCoordinates, setListOfCoordinates] = useState<GoogleCoords[]>( [] ); const searchRef: LegacyRef<HTMLInputElement> = useRef(null); const handleClickGolfCourse = (place: google.maps.places.PlaceResult) => { const lat: any = place.geometry?.location?.lat(); const lng: any = place.geometry?.location?.lng(); setCenter({ lat, lng }); setZoom(16); }; const handleClearSearchInput = () => { if (searchRef.current) { searchRef.current.value = ""; } }; const handleOnRightClick = (e: google.maps.MapMouseEvent) => { const coords: GoogleCoords = e.latLng?.toJSON() || { lat: 0, lng: 0 }; setListOfCoordinates((prev) => [...prev, coords]); }; const handleOnDragEndMarker = ( e: google.maps.MapMouseEvent, index: number ) => { const newCoords: GoogleCoords = e.latLng?.toJSON() || { lat: 0, lng: 0, }; const coordsCopy = listOfCoordinates.slice(0); coordsCopy.splice(index, 1, newCoords); setListOfCoordinates(coordsCopy); }; return ( <div style={{ padding: 8 }}> {/* Search Input */} <Autocomplete ref={searchRef} apiKey="API_KEY" // 禁用组件自动加载API脚本 loadScript={false} style={{ width: "50%", marginBottom: 8, paddingInline: 8, paddingBlock: 4, borderRadius: 8, zIndex: 100, }} options={{ types: [], componentRestrictions: { country: "us" }, }} onPlaceSelected={(place) => { handleClickGolfCourse(place); }} /> <button onClick={handleClearSearchInput} className="active:opacity-50" style={{ marginLeft: 8, borderRadius: 8, paddingInline: 8, backgroundColor: grayMid, paddingBlock: 4, }}> Clear </button> {/* Map */} <Map center={center} zoom={zoom} listOfCoordinates={listOfCoordinates} handleOnRightClick={handleOnRightClick} handleOnDragEndMarker={handleOnDragEndMarker} /> </div> ); }; export default AddGolfCoursePage;
额外建议
- 把API密钥存放在环境变量中(比如
.env.local里的NEXT_PUBLIC_GOOGLE_MAPS_API_KEY),避免硬编码泄露,使用时用process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY代替字符串"API_KEY"。 - 确保Google Cloud控制台中已经启用了Maps JavaScript API和Places API,否则功能会失效。
内容的提问来源于stack exchange,提问作者Cole
相关产品推荐
相关产品推荐

