LeafLet 在 Next JS 13 上的实现

问题描述 投票:0回答:4

我尝试在 Next JS 13.0.1 项目中实现 LeafLet 地图组件,但我在地图组件的渲染方面遇到问题。

第一次加载地图组件时,出现这个错误:

ReferenceError: window is not defined
    at eval (webpack-internal:///(sc_client)/./node_modules/leaflet/dist/leaflet-src.js:229:19)
    at eval (webpack-internal:///(sc_client)/./node_modules/leaflet/dist/leaflet-src.js:7:11)
    at eval (webpack-internal:///(sc_client)/./node_modules/leaflet/dist/leaflet-src.js:9:3)
    at Object.(sc_client)/./node_modules/leaflet/dist/leaflet-src.js (C:\desenvolvimento\estacionai-front\.next\server\app\page.js:482:1)
    at __webpack_require__ (C:\desenvolvimento\estacionai-front\.next\server\webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_client)/./node_modules/leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.js:2:18)
    at eval (webpack-internal:///(sc_client)/./node_modules/leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.js:4:2)
    at Object.(sc_client)/./node_modules/leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.js (C:\desenvolvimento\estacionai-front\.next\server\app\page.js:472:1)  
    at __webpack_require__ (C:\desenvolvimento\estacionai-front\.next\server\webpack-runtime.js:33:43)
    at eval (webpack-internal:///(sc_client)/./components/Mapa.tsx:11:91)

无论如何,地图会加载,但标记之类的东西不会出现

真正的问题是当页面重新加载时,是硬重新加载或链接引用。 出现此错误:

TypeError: Cannot read properties of undefined (reading 'default')
    at resolveModuleMetaData (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:195:82)
    at serializeModuleReference (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1298:50)
    at resolveModelToJSON (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1660:40)
    at Array.toJSON (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1081:40)
    at stringify (<anonymous>)
    at processModelChunk (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:163:36)
    at retryTask (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1823:50)
    at performWork (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1856:33)
    at AsyncLocalStorage.run (node:async_hooks:330:14)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/react-server-dom-webpack/server.browser.js:1934:55) {
  digest: '699076802'
}

出现此错误后,页面无法加载

  • 项目结构:

  • Mapa.tsx(地图组件)
'use-client';

import { useState } from 'react';
import 'leaflet/dist/leaflet.css';
import 'leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css'
import "leaflet-defaulticon-compatibility";
import { MapContainer, TileLayer, Marker, useMap } from 'react-leaflet';


export default function Map() {
  const [geoData, setGeoData] = useState({ lat: 64.536634, lng: 16.779852 });

  return (
    <MapContainer center={[geoData.lat, geoData.lng]} zoom={12} style={{ height: '90vh' }}>
      <TileLayer
         attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
         url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
       />
      {geoData.lat && geoData.lng && (
        <Marker position={[geoData.lat, geoData.lng]} />
      )}
    </MapContainer>
  );
}
  • 主页组件(app/page.tsx)
'use client';

import Link from "next/link";
import { useEffect, useState } from "react";
import Mapa from "../components/Mapa";

export default function Home(){
  
  return (
    <div>
      <Link href='/pontos'>Pontos</Link>
      <Mapa />
    </div>
  )
}

  • package.json
{
  "name": "estacionai-front",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@types/node": "18.11.9",
    "@types/react": "18.0.24",
    "@types/react-dom": "18.0.8",
    "leaflet": "^1.9.2",
    "leaflet-defaulticon-compatibility": "^0.1.1",
    "leaflet-geosearch": "^3.7.0",
    "next": "^13.0.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-leaflet": "^4.1.0",
    "typescript": "4.8.4"
  },
  "devDependencies": {
    "@types/leaflet": "^1.9.0",
    "autoprefixer": "^10.4.13",
    "postcss": "^8.4.18",
    "tailwindcss": "^3.2.1"
  }
}

我尝试使用Next中的dynamic()和import()函数,但没有成功,我认为加载组件的唯一方法是在地图组件和页面组件中使用“use client”指令

reactjs typescript next.js leaflet react-leaflet
4个回答
4
投票

您必须动态导入地图组件以强制其在客户端加载100%

const Map = dynamic(() => import("@/components/map"), {
    loading: () => <p>loading...</p>,
    ssr: false
})

2
投票

我有完全相同的问题,并且我能够通过执行以下操作来使其正常工作:

// this is your current Map file
export default function ClientMap() {
  const [geoData, setGeoData] = useState({ lat: 64.536634, lng: 16.779852 });

  return (
    <MapContainer center={[geoData.lat, geoData.lng]} zoom={12} style={{ height: '90vh' }}>
      <TileLayer
         attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
         url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
       />
      {geoData.lat && geoData.lng && (
        <Marker position={[geoData.lat, geoData.lng]} />
      )}
    </MapContainer>
  );
}
// this is a "barrel file" that prevents the ClientMap from ever getting loaded in the server.
export const Map: FunctionComponent = () => {
    const [Client, setClient] = useState<FunctionComponent>();

    useEffect(() => {
        (async () => {
            if (typeof global.window !== "undefined") {
                const newClient = (await import('./MapClient')).default
                setClient(() => newClient);
            }
        })();
    }, [])

    if (typeof global.window === "undefined" || !Client) {
        return null;
    }
    
    return Client ? <Client {...props} /> : null;
}

目标是保证传单和相关代码永远不会在服务器上执行。我在 Next 13 app dir 讨论中打开了一个线程,看看是否有更标准的方法来编写此代码here


1
投票

我也遇到这个问题了,有时会,有时不会。也不是最有帮助的错误消息...

但是,我确实注意到“app/”中可能有页面“api/”,根据文档,该页面目前应该保留在“pages/”中:https://beta.nextjs.org/docs /数据获取/api-routes。可能不会解决任何问题,但可能会防止未来出现一些问题。


0
投票

该问题主要发生在您使用应用程序路由时。该传单未针对 NextJs 进行优化。 这可以通过动态导入组件来解决。 你可以通过NextJs1官方文档学习动态加载。

import dynamic from 'next/dynamic';
const Mapa = dynamic(() => import('../components/Mapa'), { 
ssr: false,
})

然后使用您的组件。

© www.soinside.com 2019 - 2024. All rights reserved.