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

React-leaflet服务端渲染出现window undefined错误如何解决?

问题根因

你当前的写法存在两个核心问题,直接导致服务端渲染阶段依然触发window is not defined报错:

  1. 顶部直接导入了react-leaflet的相关组件,服务端渲染阶段执行导入逻辑时,react-leaflet内部依赖window对象的代码会直接执行,和你在useEffect中是否动态导入leaflet.js无关
  2. 未做加载状态判断,无论leaflet依赖是否加载完成,都直接渲染MapContainer等地图组件,服务端渲染阶段会直接执行组件逻辑触发报错
修复步骤
  • 移除顶部的react-leaflet组件导入逻辑,改为仅在客户端侧动态导入react-leaflet和leaflet依赖,避免服务端执行相关代码
  • 增加加载状态判断,仅在依赖加载完成后再渲染地图组件,服务端渲染阶段返回占位元素即可
  • 若使用Next.js这类SSR框架,可直接使用框架提供的动态导入能力关闭组件的SSR渲染,写法更简洁
代码示例

通用SSR方案

import React, { useEffect, useState } from 'react';
import 'leaflet/dist/leaflet.css';

const MyMapComponent = () => {
  const [LeafletComponents, setLeafletComponents] = useState(null);

  useEffect(() => {
    const initLeaflet = async () => {
      // 仅在客户端环境动态导入leaflet和react-leaflet
      await import('leaflet/dist/leaflet.js');
      const { MapContainer, TileLayer, Marker, Popup } = await import('react-leaflet');
      setLeafletComponents({ MapContainer, TileLayer, Marker, Popup });
    };
    initLeaflet();
  }, []);

  // 依赖加载完成前返回占位元素
  if (!LeafletComponents) return <div style={{ height: '400px' }}>地图加载中...</div>;

  const { MapContainer, TileLayer, Marker, Popup } = LeafletComponents;
  return (
    <MapContainer center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false} style={{ height: '400px', width: '100%' }}>
      <TileLayer
        attribution='&copy; OpenStreetMap contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
      <Marker position={[51.505, -0.09]}>
        <Popup>
          A pretty CSS3 popup. <br /> Easily customizable.
        </Popup>
      </Marker>
    </MapContainer>
  );
};

export default MyMapComponent;

Next.js 专属简化方案

首先将地图逻辑单独抽为组件文件MyMapComponent.jsx,写普通的react-leaflet逻辑无需额外处理,在使用组件的位置按如下方式导入:

import dynamic from 'next/dynamic';

// 动态导入地图组件,关闭SSR渲染
const MyMapComponent = dynamic(() => import('./MyMapComponent'), {
  ssr: false,
  loading: () => <div style={{ height: '400px' }}>地图加载中...</div>
});

// 业务代码直接调用即可
const Page = () => {
  return <MyMapComponent />
};
额外注意事项

如果后续出现Marker图标不显示的问题,可在leaflet加载完成后手动配置默认图标路径:

import L from 'leaflet';
delete L.Icon.Default.prototype._getIconUrl;
L.Icon.Default.mergeOptions({
  iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
  iconUrl: require('leaflet/dist/images/marker-icon.png'),
  shadowUrl: require('leaflet/dist/images/marker-shadow.png'),
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 11:15:00