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

Next.js中导入Leaflet及自定义Icon的SSR问题与解决方案

Next.js 集成 Leaflet 自定义 Icon 的 SSR 兼容解决方案

最近在Next.js项目里集成Leaflet地图时踩了个SSR的坑——Leaflet本身不支持服务端渲染,一开始我尝试逐个动态导入Leaflet和react-leaflet的相关组件,并关闭SSR支持,代码如下:

import React, {Component} from "react";
import dynamic from 'next/dynamic';
const L = dynamic( () => import("leaflet/"), { ssr: false } )
const Map = dynamic( () => import("react-leaflet/lib/Map"), { ssr: false } )
const Marker = dynamic( () => import("react-leaflet/lib/Marker"), { ssr: false } )
const TileLayer = dynamic( () => import("react-leaflet/lib/TileLayer"), { ssr: false } )
const Popup = dynamic( () => import("react-leaflet/lib/Popup"), { ssr: false } )
var myIcon = L.icon({
iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',
iconSize: [38, 95],
iconAnchor: [22, 94],
//popupAnchor: [-3, -76],
//shadowUrl: 'my-icon-shadow.png',
//shadowSize: [68, 95],
//shadowAnchor: [22, 94]
});
class Benemap extends Component {
state = {
lat: 1.3521,
lng: 103.8198,
zoom: 13,
}
render () {
const position = [this.state.lat, this.state.lng]
return (
<Map className="map" center={position} zoom={this.state.zoom}>
<TileLayer attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker position={position} icon = {myIcon} >
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</Map>
);
}
}
export default Benemap;

但当我单独编写自定义Icon的代码段时:

const L = dynamic( () => import("leaflet/"), { ssr: false } )
var myIcon = L.icon({
iconUrl: 'https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon-2x.png',
iconSize: [38, 95],
iconAnchor: [22, 94],
//popupAnchor: [-3, -76],
//shadowUrl: 'my-icon-shadow.png',
//shadowSize: [68, 95],
//shadowAnchor: [22, 94]
});

本地开发服务器直接报错了。我当时找了好久没找到现成方案,后来在Antoni Kepinski的帮助下终于解决了——不要逐个动态导入Leaflet相关依赖,而是将整个包含Leaflet逻辑的组件进行动态导入并关闭SSR。

这样做之后,就能像平时在纯客户端项目里一样正常使用Leaflet的API和自定义Icon了,唯一的小缺点就是这个客户端组件的渲染速度会比服务端渲染的组件慢一些。

示例代码如下:

import dynamic from 'next/dynamic';
const Benemap = dynamic(() => import('../components/analytics/Benemap'), {
loading: () => 'Loading...',
ssr: false,
});
// use back with auth
export default withAuth(function Home({ initialState, secondinitialState }) {
console.log('one');
const isAuthenticated = useIsAuthenticated();
const name = getName();
const role = getRole();
console.log(name);
return (
<div className='flex flex-col h-screen'>
<Header />
<SubHeader name={name} role={role} />
<div className='antialiased bg-gray-200 flex-grow'>
<Graph1 data={initialState} />
<Benemap name={name} />
<Graph2 anotherdata={secondinitialState} />
</div>
<Footer />
</div>
);
});

内容的提问来源于stack exchange,提问作者oden209

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 17:37:44