alex3165 / react-mapbox-gl

A React binding of mapbox-gl-js
http://alex3165.github.io/react-mapbox-gl/
MIT License
1.93k stars 536 forks source link

GeoJSONLayer vs map.addLayer / Layer #1030

Closed iamdangavin closed 8 months ago

iamdangavin commented 9 months ago

Trying to understand the GeoJSONLayer component. I am fetching data and creating a geojson object on the fly on page render. I have set up a state to only render the map once the data has been set. However, I cannot get GeoJSONLayer to work.

No LineString renders:

<Map
  style="{style}"
>
  <GeoJSONLayer
    data={geoJson}
    lineLayout={{
      visibility: "visible",
      "line-join": "round",
      "line-cap": "round",
    }}
    linePaint={{
      "line-width": 6,
      "line-color": "#f8f9fa",
    }}
  />
</Map>

This renders the LineString:

<Map
  style="{style}"
  onStyleLoad={(map) => {
    map.addLayer({
      id: "routes",
      type: "line",
      source: {
        type: "geojson",
        data: geoJson.features[0],
      },
    });
  }}
>
  <Layer type="line" id="router" sourceId="routes" />
</Map>

Both methods are returned like this:

{geoJson ? (
  <Map>...</Map>
):(<Loader />)}

What am I missing? I have tried it with smaller sample data that isn't fetched and the GeoJSONLayer still doesn't render.

iamdangavin commented 9 months ago

Upon further inspection it looks like even doing a simple implementation it seems as though my map is rendering twice on the page and in neither instance is the controls or popup working...

This is driving me nuts. I will state. I am slowing building up complexity within React and this one has me stumped...

image

Component:

"use client";
import ReactMapboxGl, {
  ZoomControl,
  ScaleControl,
  RotationControl,
  Popup,
} from "react-mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";

const Mapbox = ReactMapboxGl({
  accessToken: process.env.NEXT_PUBLIC_MAPBOX_API_KEY,
});

export const Routes = () => {
  return (
    <Mapbox
      style="mapbox://styles/mapbox/streets-v11"
      containerStyle={{
        height: "100vh",
        width: "100%",
      }}
      onStyleLoad={(map) => console.log("Map loaded", map)}
    >
      <ZoomControl />
      <ScaleControl />
      <RotationControl />
      <Popup
        coordinates={[-0.13235092163085938, 51.518250335096376]}
        offset={{
          "bottom-left": [12, -38],
          bottom: [0, -38],
          "bottom-right": [-12, -38],
        }}
      >
        <h1>Popup</h1>
      </Popup>
    </Mapbox>
  );
};

Next.js / page.jsx

import { Routes } from "@/components/maps/routes";

export default function Index() {
  return (
    <>
      <main>
        <Routes />
      </main>
    </>
  );
}

Update

It appears that Next.js is mounting, unmounting, and then mounting again so there is no cleanup of the initial <Mapbox/>, thus the dual maps rendering on the page... A remove call was needed on the unmount on my end. To be clear, this only happens during local development not during production build/serve.