Technical Guide : Setup NextJS with Leaflet

Setup NextJS

you can create next js with create-next-js-app

npx create-next-app nextjs-leaflet
# or
yarn create next-app nextjs-leaflet

or use template like starter nextjs tailwindcss

npx degit sozonome/nextarter-tailwind nextjs-leaflet
cd nextjs-leaflet

Setup Leaflet

Because leaflet its not reactjs, we need dependencies for reactjs with react-leaflet. Docs about react-leaflet can read here

yarn add leaflet react-leaflet

if you're using typescript, its react-leaflet support typescript too.

yarn add -D @types/leaflet

Create Map Components

Take a Note, my components look like this:

First, we create Map Components in src/lib/components

import L from 'leaflet';
import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';

const Maps = () => {
  const icon = L.icon({ iconUrl: '/images/marker-icon.png' });

  return (
    <div className="w-full">
      <MapContainer
        className="h-[300px] w-full"
        center={[51.505, -0.09]}
        zoom={13}
        scrollWheelZoom={false}
      >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        <Marker position={[51.505, -0.09]} icon={icon}>
          <Popup>
            A pretty CSS3 popup. <br /> Easily customizable.
          </Popup>
        </Marker>
      </MapContainer>
    </div>
  );
};

export default Maps;

Explain :

Import Statements:

  • import L from 'leaflet';: This line imports the Leaflet library, a JavaScript library for interactive maps. L is a conventional shorthand used to refer to Leaflet.
  • import { MapContainer, Marker, Popup, TileLayer } from 'react-leaflet';: This line imports specific components from the react-leaflet package. These components are React-friendly wrappers for corresponding Leaflet functionalities.

Component Definition - Maps:

  • const Maps = () => { ... };: This line defines a functional component named Maps in React.

Leaflet Icon Configuration:

  • const icon = L.icon({ iconUrl: '/images/marker-icon.png' });: This creates a custom icon for map markers using Leaflet's icon method. The icon image is loaded from the specified URL (/images/marker-icon.png).
  • The issue arises due to the malfunctioning of the default icons provided by react-leaflet, necessitating the creation of custom icons.

Rendering the Map:

  • <div className="w-full">...</div>: The map is wrapped inside a div element with a full width. This div acts as a container for the map.
  • <MapContainer className="h-[300px] w-full" center={[51.505, -0.09]} zoom={13} scrollWheelZoom={false}>... </MapContainer>: This is the root component for the map. It uses the following props:
  • className="h-[300px] w-full": Sets the height and width of the map.
  • center={[51.505, -0.09]}: Sets the initial geographical center of the map (latitude and longitude).
  • zoom={13}: Sets the initial zoom level of the map.
  • scrollWheelZoom={false}: Disables zooming in/out using the mouse scroll wheel.

Tile Layer Configuration:

  • <TileLayer ... />: This component is used to display the map tiles (the visual imagery of the map).
  • attribution='...': Provides attribution text for the map tiles, which is a requirement for many free tile providers like OpenStreetMap.
  • url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png": Specifies the URL template for loading map tiles. {s}, {z}, {x}, and {y} are placeholders that Leaflet replaces with actual values when making requests for tiles.

Marker Configuration:

  • <Marker position={[51.505, -0.09]} icon={icon}> ... </Marker>: Places a marker on the map.
  • position={[51.505, -0.09]}: Sets the geographical coordinates where the marker is placed.
  • icon={icon}: Applies the custom icon created earlier to this marker.

Popup Configuration:

  • <Popup> ... </Popup>: Defines a popup that appears when you click on the marker.
  • The content inside the <Popup> tags (A pretty CSS3 popup. <br /> Easily customizable.) is the text displayed in the popup.

Export Statement:

  • export default Maps;: This line exports the Maps component, making it available for import and use in other parts of the application.

Overall, this Maps component renders an interactive map centered at a specific geographical point, with a single marker using a custom icon. When clicked, this marker shows a customizable popup with text.

Second, we import css from leaflet in layout.tsx

...
import 'leaflet/dist/leaflet.css';
import '@/lib/styles/globals.css';
...

Explain:

This ensures that the necessary CSS for creating a Leaflet map is present, allowing for the proper display and functionality of the map.

Third, we call Maps components and show it home components

'use client';

import type { NextPage } from 'next';
import dynamic from 'next/dynamic';

import SomeText from '@/lib/components/samples/SomeText';

const Home: NextPage = () => {
  const NotSSRMaps = dynamic(() => import('@/lib/components/maps'), {
    ssr: false,
  });

  return (
    <div className="mx-auto flex min-h-[60vh] w-full max-w-screen-lg flex-col items-center justify-center gap-8 text-center">
      <SomeText />
      <NotSSRMaps />
    </div>
  );
};

export default Home;

Client-Side Only Directive:

  • 'use client';: This is a directive indicating that the code should only run on the client-side. It's specific to Next.js 12 and later versions, allowing you to specify per-module whether the code is intended for the server, client, or both.

Dynamic Import of NotSSRMaps Component:

  • const NotSSRMaps = dynamic(() => import('@/lib/components/maps'), { ssr: false });: Here, the dynamic function is used to import the maps component (@/lib/components/maps) dynamically. The option { ssr: false } indicates that this component should not be rendered on the server during server-side rendering. This is often necessary for components that rely on window or other browser-specific APIs, which are not available during SSR.

If everything is correct, it should display something like this:

Full Code:

nextjs-leaflet/src/lib/pages/home/index.tsx at main · naufaldi/nextjs-leaflet
Setup NextJS with leaflet. Contribute to naufaldi/nextjs-leaflet development by creating an account on GitHub.