Load markers dynamically with react and mapbox gl or maplibre gl

1k Views Asked by At

I am learning React. I want to display a map on which markers are dynamically shown and hidden. This works. I use Maplibre GL, which is a fork of Mapbox GL and the handling is the same.

Unfortunately, however, when the markers are changed, the map is reloaded because a dependency is specified in the useEffect-Hook. Without it, however, the markers do not change. I cannot access the map (variable map) outside of useEffect. What possibilities are there to prevent the map from being reloaded, but to adjust the markers dynamically.

This is my code:

import React from "react";
import maplibregl from "maplibre-gl";

const App = () => {
  const pois = [
    {
      display_name: "backery a",
      icon: "https://nominatim.openstreetmap.org/ui/mapicons//shopping_bakery.p.20.png",
      lat: "50.4",
      lon: "7.1",
      importance: "0.111",
      geojson: '{"type":"Point","coordinates":[7.1,50.4]}',
      place_id: "1",
    },
    {
      display_name: "backery b",
      icon: "https://nominatim.openstreetmap.org/ui/mapicons//shopping_bakery.p.20.png",
      lat: "51.4",
      lon: "6.1",
      importance: "0.211",
      geojson: '{"type":"Point","coordinates":[6.1,51.4]}',
      place_id: "2",
    },
  ];

  const [searchTerm, setSearchTerm] = React.useState(
    localStorage.getItem("search") || "backery a"
  );

  React.useEffect(() => {
    localStorage.setItem("search", searchTerm);
  }, [searchTerm]);

  const handleSearch = (event) => {
    setSearchTerm(event.target.value);
  };

  const searchedpois = pois.filter((poi) =>
    poi.display_name.toLowerCase().includes(searchTerm.toLowerCase())
  );

  return (
    <div>
      <h1>React Maplibre Map</h1>
      <Search searchValue={searchTerm} onSearch={handleSearch} />
      <hr />
      <List list={searchedpois} />
      <hr />
      <Map list={searchedpois} />
    </div>
  );
};

const Map = (props) => {
  React.useEffect(() => {
    const map = new maplibregl.Map({
      container: "map",
      style:
        "https://api.maptiler.com/maps/streets/style.json?key=mykey",
      center: [7.5, 50.1],
      zoom: 4,
    });

    map.on("load", () => {
      props.list.map((item) =>
        new maplibregl.Marker().setLngLat([item.lon, item.lat]).addTo(map)
      );
    });
  }, [props.list]);

  return <div></div>;
};

const Search = ({ searchValue, onSearch }) => (
  <div>
    <label htmlFor="search">Suche: </label>
    <input id="search" type="text" onChange={onSearch} value={searchValue} />
  </div>
);

const List = (props) => (
  <div>
    <table>
      <tbody>
        {props.list.map((item) => (
          <POI key={item.place_id} poi={item} />
        ))}
      </tbody>
    </table>
  </div>
);

const POI = ({ poi }) => (
  <tr key={poi.place_id}>
    <td>{poi.display_name}</td>
    <td>{poi.lat}</td>
    <td>{poi.lon}</td>
    <td>{poi.importance}</td>
    <td>
      <img alt="" src={poi.icon} />
    </td>
  </tr>
);

export default App;
0

There are 0 best solutions below