Search code examples
javascriptreactjstypescriptnext.jsreact-leaflet

Getting errors when rendering a component with dynamic in Next.js


I am trying to render Leaflet maps in Next.js using Typescript. I read that ssr needed to be disabled to avoid the 'window not defined' problem, but when trying this to generate the map:

import React from "react";
import { MapContainer, TileLayer } from "react-leaflet";

export const Leaflet: React.FC = () => {
  return (
    <MapContainer center={{ lat: 48.71291, lng: 44.52693 }} zoom={13}>
      <TileLayer
        attribution='&copy; <a href="http://osm.org/copyright%22%3EOpenStreetMap</a> contributors'
        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
      />
    </MapContainer>
  );
};

and this to render it:

const Home: NextPage = () => {
  const MapWithNoSSR = dynamic(() => import("../components/Leaflet"), {
    ssr: false,
  });

  return (
    <>
      <MapWithNoSSR/>
    </>
    );
  };

export default Home

TypesSript gives me this error:

Argument of type '() => Promise<typeof import("/src/components/Leaflet")>' is not assignable to parameter of type 'DynamicOptions<{}> | Loader<{}>'. Type '() => Promise<typeof import("/src/components/Leaflet")>' is not assignable to type '() => LoaderComponent<{}>'.

And the browser gives this error:

Error: Element type is invalid. Received a promise that resolves to: [object Module]. Lazy element type must resolve to a class or function.

Has anyone here experienced something similar and have some advice regarding how to solve it?


Solution

  • You are getting those errors because your Leaflet component is a named module, and you are trying to access it as if it was a default one. Change your code to as the doc says:

    import { NextPage } from "next";
    import dynamic from "next/dynamic";
    
    // ⚠️: .then() is needed because the component is not exported with the default keyword
    const MapWithNoSSR = dynamic(
      () => import("../components/Leaflet").then((module) => module.Leaflet),
      {
        ssr: false,
      }
    );
    
    const Home: NextPage = () => {
      return (
        <>
          <MapWithNoSSR />
        </>
      );
    };
    
    export default Home;
    

    Also, notice I pushed the dynamic import outside of Home.