在Next.js中使用React-leaflet出现window未定义错误,求解决方案
解决Next.js中React-Leaflet的Window Undefined错误
问题根源
Next.js默认服务端渲染(SSR)环境不存在window对象,而React-Leaflet依赖浏览器环境的window,直接导入会导致服务端渲染阶段触发报错。
正确解决方案
1. 确保依赖安装
未安装依赖的话执行以下命令:
npm install react-leaflet leaflet # 或 yarn add react-leaflet leaflet
2. 动态导入地图组件(禁用SSR)
用Next.js的dynamic工具导入地图组件,明确禁用服务端渲染,确保组件只在客户端加载。
在使用地图的页面文件(比如pages/map.js)中修改导入方式:
import dynamic from 'next/dynamic'; // 动态导入地图组件,禁用SSR const OpenStreetMap = dynamic(() => import('../components/OpenStreetMap'), { ssr: false, loading: () => <div>加载地图中...</div> // 可选加载占位 }); export default function MapPage() { return <OpenStreetMap />; }
3. 引入Leaflet样式
在pages/_app.js中全局引入Leaflet的CSS,否则地图瓦片会显示异常:
// pages/_app.js import 'leaflet/dist/leaflet.css'; export default function App({ Component, pageProps }) { return <Component {...pageProps} />; }
4. 修复Marker图标显示(可选)
如果Marker图标不显示,在地图组件中手动设置图标路径:
import L from 'leaflet'; delete L.Icon.Default.prototype._getIconUrl; L.Icon.Default.mergeOptions({ iconRetinaUrl: '/leaflet/images/marker-icon-2x.png', iconUrl: '/leaflet/images/marker-icon.png', shadowUrl: '/leaflet/images/marker-shadow.png', });
需要把node_modules/leaflet/dist/images下的图标文件复制到项目public/leaflet/images目录中。
组件代码调整(可选)
如果不想拆分组件,也可以在组件内部通过useEffect确保仅在客户端渲染地图:
import React, { useRef, useState, useEffect } from "react"; const OpenStreetMap = () => { const [center, setCenter] = useState({ lat: 23.729211164246585, lng: 90.40874895549243, }); const mapRef = useRef(); const [Map, setMap] = useState(null); const [TileLayer, setTileLayer] = useState(null); const [Marker, setMarker] = useState(null); const [Popup, setPopup] = useState(null); useEffect(() => { // 客户端动态导入react-leaflet组件 const importComponents = async () => { const { Map, TileLayer, Marker, Popup } = await import('react-leaflet'); setMap(Map); setTileLayer(TileLayer); setMarker(Marker); setPopup(Popup); }; importComponents(); }, []); const attribution = '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'; const url = "https://api.maptiler.com/maps/basic-v2/256/{z}/{x}/{y}.png?key=puoG6vOLC4oqJXcum8fR"; if (!Map) return <div>加载地图中...</div>; return ( <div style={{ height: '500px', width: '100%' }}> {/* 必须设置容器尺寸 */} <Map center={center} zoom={9} ref={mapRef} style={{ height: '100%' }}> <TileLayer attribution={attribution} url={url} /> <Marker position={[23.729211164246585, 90.40874895549243]}> <Popup>This is a popup.</Popup> </Marker> </Map> </div> ); }; export default OpenStreetMap;
注意:地图容器必须设置明确高度,否则地图会无法显示。
内容的提问来源于stack exchange,提问作者Brinless_Loco
相关产品推荐
相关产品推荐

