Next.js SSG中Leaflet Canvas Marker的数据获取方案抉择
解决Next.js SSG中Leaflet Canvas Marker导入GeoJSON数据的问题
针对你的场景,提供两种适配SSG模式的可行方案,根据数据更新频率选择即可:
方案一:构建时通过getStaticProps获取数据(推荐SSG静态数据场景)
这种方式在Next.js构建阶段就获取GeoJSON数据,作为静态props传入组件,完全适配SSG模式,避免客户端额外请求,加载速度更快。
步骤1:修改页面代码,添加getStaticProps
import Head from 'next/head' import dynamic from 'next/dynamic'; // 动态导入Map组件,禁用SSR const MapWithNoSSR = dynamic(() => import("../components/Map"), { ssr: false }); const MapPage = ({ locations }) => { return ( <div> <Head> <title>Map of Peng spots</title> </Head> <h1>Map of Peng spots</h1> <p>Map should go here!</p> {/* 将构建时获取的GeoJSON数据传给Map组件 */} <MapWithNoSSR locations={locations} /> </div> ) } // 构建阶段获取数据(运行在服务器/构建环境) export async function getStaticProps() { try { // 推荐直接调用API路由的处理函数(避免构建时网络请求) // 示例:import { getLocations } from '../pages/api/getlocations'; // const locations = await getLocations(); // 若必须用fetch,确保构建时能访问API地址 const res = await fetch('http://mysite:3000/api/getlocations'); const locations = await res.json(); return { props: { locations }, // 可选:配置增量静态再生,定期更新数据 // revalidate: 86400 // 24小时 }; } catch (error) { console.error('获取位置数据失败:', error); return { props: { locations: [] } }; } } export default MapPage
步骤2:修改Map组件,传递数据给Canvas组件
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet' import 'leaflet/dist/leaflet.css' import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css' import 'leaflet-defaulticon-compatibility'; import LeafletCanvasMarker from './Pengs'; // 接收页面传来的locations props const Map = ({ locations }) => { return ( <MapContainer center={[50.1109, 8.6821]} zoom={14} scrollWheelZoom={false} style={{height: "100vh", width: "100%"}}> <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors" /> <Marker position={[50.1109, 8.682]} draggable={true} animate={true} > <Popup> Hey ! you found me </Popup> </Marker> {/* 将locations传给Canvas组件 */} <LeafletCanvasMarker locations={locations} /> </MapContainer> ) } export default Map
步骤3:修改Canvas图层组件,处理GeoJSON数据
import { useEffect } from "react"; import { useMap } from "react-leaflet"; import "leaflet-canvas-marker"; import L from "leaflet"; export default function LeafletCanvasMarker({ locations }) { const map = useMap(); useEffect(() => { if (!map || !locations?.features?.length) return; const ciLayer = L.canvasIconLayer({}).addTo(map); ciLayer.addOnClickListener(function (e, data) { console.log(data); }); ciLayer.addOnHoverListener(function (e, data) { console.log(data[0]?.data?._leaflet_id); }); const icon = L.icon({ iconUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png", iconSize: [20, 18], iconAnchor: [10, 9], }); // 转换GeoJSON坐标:Leaflet用[lat,lng],GeoJSON是[lng,lat] const markerLayers = locations.features.map(feature => { const [lng, lat] = feature.geometry.coordinates; return L.marker([lat, lng], { icon }) .bindPopup(`<div>${feature.properties.name || 'Unknown Spot'}</div>`); // 根据你的GeoJSON属性调整 }); ciLayer.addLayers(markerLayers); // 组件卸载时清理图层 return () => { map.removeLayer(ciLayer); }; }, [map, locations]); return null; }
方案二:客户端通过useEffect获取数据(适配动态数据场景)
如果GeoJSON数据需要频繁更新,或构建时无法获取数据,可以在Canvas组件内部发起客户端请求,这种方式依然适配SSG(页面本身静态生成,数据在客户端加载)。
修改Canvas图层组件即可
import { useEffect, useState } from "react"; import { useMap } from "react-leaflet"; import "leaflet-canvas-marker"; import L from "leaflet"; export default function LeafletCanvasMarker() { const map = useMap(); const [locations, setLocations] = useState(null); const [loading, setLoading] = useState(true); // 客户端请求API获取数据 useEffect(() => { if (!map) return; const fetchLocations = async () => { try { const res = await fetch('/api/getlocations'); // 用相对路径即可 const data = await res.json(); setLocations(data); } catch (error) { console.error('加载位置数据失败:', error); } finally { setLoading(false); } }; fetchLocations(); }, [map]); // 数据加载完成后渲染Canvas标记 useEffect(() => { if (!map || !locations?.features?.length || loading) return; const ciLayer = L.canvasIconLayer({}).addTo(map); ciLayer.addOnClickListener(function (e, data) { console.log(data); }); ciLayer.addOnHoverListener(function (e, data) { console.log(data[0]?.data?._leaflet_id); }); const icon = L.icon({ iconUrl: "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png", iconSize: [20, 18], iconAnchor: [10, 9], }); const markerLayers = locations.features.map(feature => { const [lng, lat] = feature.geometry.coordinates; return L.marker([lat, lng], { icon }) .bindPopup(`<div>${feature.properties.name || 'Unknown Spot'}</div>`); }); ciLayer.addLayers(markerLayers); return () => { map.removeLayer(ciLayer); }; }, [map, locations, loading]); return null; }
关键注意事项
- 方案一中,
getStaticProps运行在服务器/构建环境,可直接连接PostGIS数据库(无需通过API路由),效率更高。 - 处理GeoJSON时必须转换坐标顺序:Leaflet使用
[纬度, 经度],而GeoJSON标准是[经度, 纬度]。 - 若使用增量静态再生(
revalidate),Next.js会在后台自动更新页面数据,无需重新部署。
内容的提问来源于stack exchange,提问作者nizz0k
相关产品推荐
相关产品推荐

