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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 12:36:16