如何在Next.js中正确加载并使用Google Maps API
Next.js 加载使用 Google Maps API 正确实现
报错核心原因
你之前把next/script组件写在_document.js的<Head />内部属于无效写法:next/document导出的Head组件仅支持解析原生HTML标签,不会处理Next.js封装的自定义Script组件,脚本不会按照你设定的策略加载,全局window对象下自然不存在google属性,直接调用就会报未定义错误。
正确加载API的方式
根据你的使用场景选一种即可,不要重复加载脚本:
全局加载(所有页面都要用的场景)
把脚本加载逻辑移到_app.jsx(Pages Router)或者根layout.jsx(App Router)中,不要放在_document里:
// pages/_app.jsx (Pages Router) import Script from 'next/script' import '@/styles/globals.css' export default function App({ Component, pageProps }) { return ( <> <Script src={`https://maps.googleapis.com/maps/api/js?key=${process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}&libraries=places`} strategy="beforeInteractive" /> <Component {...pageProps} /> </> ) }
按需加载(仅单个/部分页面使用的场景)
直接在用到地图能力的页面/组件内引入Script即可,不需要全局加载,性能更好:
// 对应业务组件内 import Script from 'next/script' export default function MapPage() { return ( <> <Script src={`https://maps.googleapis.com/maps/api/js?key=${process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}&libraries=places`} strategy="afterInteractive" /> {/* 页面其他内容 */} </> ) }
正确调用API的方法
Google Maps脚本是异步加载的,不能在组件初始化时直接同步调用window.google.maps,必须等脚本加载完成后再执行相关逻辑,两种常用实现:
原生写法(不用第三方库)
利用Script组件自带的onLoad回调,确认脚本加载完成后再调用API:
'use client' // App Router下需要加该行标记客户端组件,Pages Router无需添加 import { useState } from 'react' import Script from 'next/script' export default function PlaceSearch() { const [searchResults, setSearchResults] = useState([]) const handleMapsReady = () => { // 此时window.google已挂载,可以安全调用API const service = new window.google.maps.places.AutocompleteService() service.getPlacePredictions( { input: '上海人民广场' }, (results, status) => { if (status === window.google.maps.places.PlacesServiceStatus.OK) { setSearchResults(results) } } ) } return ( <div> <Script src={`https://maps.googleapis.com/maps/api/js?key=${process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}&libraries=places`} onLoad={handleMapsReady} /> <ul> {searchResults.map(place => ( <li key={place.place_id}>{place.description}</li> ))} </ul> </div> ) }
如果逻辑写在useEffect里,可以加状态判断确认google对象存在再执行,避免调用时机过早。
第三方库使用注意事项
你提到的两个地址自动补全库本身可以正常使用,失效基本是以下原因导致:
- 脚本重复加载,导致全局google对象被覆盖
- Google Cloud控制台未开启对应服务:必须开启Maps JavaScript API和Places API两个服务,否则接口会返回权限错误
- 环境变量配置错误:变量名必须带
NEXT_PUBLIC_前缀,否则客户端代码无法读取到API Key,脚本加载时会因为缺少key参数失败 - API Key未配置正确的域名白名单,生产环境会被Google拦截请求
常见踩坑提示
- 所有和Google Maps相关的逻辑都要放在客户端执行,不要在服务端组件、getServerSideProps、generateMetadata等服务端执行的代码块里访问window.google,服务端不存在window对象
- 用TypeScript的话直接安装
@types/google.maps就能获得完整的类型提示,不需要手动给window对象声明google属性 - 如果脚本加载后控制台报API错误,优先去Google Cloud控制台查API启用状态、Key的权限配置、配额是否用完
内容的提问来源于stack exchange,提问作者grabury
相关产品推荐
相关产品推荐

