返回

在服务端渲染时导入必须使用客户端window对象的高德地图组件+解决‘window is not defined’的报错

前端

在 Next.js 中集成高德地图,告别 “window is not defined”

问题背景

在 Next.js 应用程序中集成高德地图时,开发者可能会遇到一个棘手的错误:window is not defined。这是因为在服务端渲染 (SSR) 过程中,window 对象并不存在。

解决方案:动态导入

为了解决这个问题,我们可以采用动态导入技术。动态导入是一种 JavaScript 特性,允许我们在运行时加载模块。这意味着我们可以在客户端环境中加载高德地图组件,从而避免在 SSR 中引发错误。

实现步骤

  1. 安装高德地图包:
npm install @amap/amap-jsapi
  1. 创建 _document.js 文件:

pages 文件夹中创建 _document.js 文件,并添加以下代码:

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head>
          <script async defer src="https://webapi.amap.com/maps?v=2.0&key=YOUR_API_KEY"></script>
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

这将异步加载高德地图 API 脚本。

  1. 页面组件集成:

在页面组件中,使用 useRefuseEffect 钩子在客户端环境中初始化地图:

import React, { useRef, useEffect } from 'react'

const Page = () => {
  const mapRef = useRef()

  useEffect(() => {
    // 在客户端初始化地图
    const map = new AMap.Map(mapRef.current)
  }, [])

  return (
    <div>
      <div ref={mapRef} style={{ width: '100%', height: '500px' }}></div>
    </div>
  )
}

export default Page
  1. next.config.js 配置:

next.config.js 文件中,设置 reactStrictModetrue

module.exports = {
  reactStrictMode: true,
}

总结

通过动态导入,我们成功解决了 Next.js SSR 中的 window is not defined 错误,从而可以在页面组件中轻松使用高德地图组件。

常见问题解答

  1. 为什么在服务端渲染中会出现 window is not defined 错误?
    由于 window 对象是浏览器环境中的全局对象,而在服务端渲染过程中并不存在。

  2. 动态导入是如何解决这个问题的?
    动态导入允许我们在客户端环境中加载高德地图组件,从而避免在服务端渲染中使用 window 对象。

  3. 在服务端渲染中使用高德地图组件有什么好处?
    在服务端渲染中使用高德地图组件可以提高页面的初始加载速度,因为地图组件可以在页面加载时就初始化。

  4. 我应该将高德地图 API 脚本放在哪里?
    建议将高德地图 API 脚本放在 _document.js 文件中,以确保在所有页面上加载。

  5. 我可以在页面组件中使用 window 对象吗?
    可以在客户端环境中使用 window 对象,但请确保只在必要时使用,因为在服务端渲染中使用 window 对象会导致错误。