ReactJS - پیادهسازی LeafLet در Next JS 13
من در حال تلاش برای پیادهسازی یک کامپوننت نقشه LeafLet در پروژه Next JS 13.0.1 خود هستم، اما در رندر کردن کامپوننت نقشه با مشکل مواجه هستم.
در اولین بارگذاری مؤلفه نقشه، این خطا ظاهر میشود:
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)
به هر حال، نقشه بارگذاری میشود، اما چیزهایی مثل نشانها ظاهر نمیشوند
مشکل واقعی زمانی است که صفحه دوباره بارگذاری میشود، چه بارگذاری سخت باشد و چه ارجاع Link. این خطا ظاهر میشود:
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='© <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>
)
}
- پکیج.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"
}
}
من سعی کردم از توابع dynamic() و import() در Next استفاده کنم اما بدون موفقیت، فکر میکنم تنها راه بارگذاری کامپوننت استفاده از دستور 'use client' در هر دو کامپوننت نقشه و صفحه است
پاسخ شماره ۱
شما باید کامپوننت نقشه را به صورت پویا ایمپورت کنید تا آن را مجبور کنید 100٪ در سمت کلاینت بارگذاری شود
const Map = dynamic(() => import("@/components/map"), {
loading: () => <p>loading...</p>,
ssr: false
})
پاسخ شماره ۲
من دقیقاً همان مشکل را دارم و توانستم با انجام کاری شبیه به این آن را درست کنم:
// 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='© <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 باز کردم تا ببینم آیا روش استانداردتری برای نوشتن این کد اینجا وجود دارد یا نه.



