1

I am new at react redux (and hooks) and I've been following this general tutorial:

I'm also interested in using react-leaflet, which at the time of this writing is on v3 which uses hooks. I've gotten as far as being able to load data containing an array of latlng to generate markers:

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { Map, MapContainer, Marker, Popup, TileLayer, useMap } from "react-leaflet";
import { Icon } from "leaflet";
import "../../css/app.css";
import { useSelector, useDispatch } from "react-redux";
import { getMarkers, selectMarkers } from "../features/markerSlice";

export const LeafMap = () => {
    //marker state
    const stateMarker = useSelector(state => state.marker);
    const dispatch = useDispatch();
    useEffect(() => {dispatch(getMarkers());}, [dispatch]);

    // map state
    const stateMap = useSelector(state => state.map)

    if (stateMarker.markers.length > 0) {
        return (
            <MapContainer center={stateMap.center} zoom={stateMap.zoom} scrollWheelZoom={true}>
              <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
              {stateMarker.markers.map(el => (
                <Marker position={[el.latitude, el.longitude]}/>
              ))}
            </MapContainer>
        );
    } else {
        return (
            <MapContainer center={stateMap.center} zoom={stateMap.zoom} scrollWheelZoom={true}>
              <TileLayer
                attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
            </MapContainer>
        );
    }

}

At the moment, I'm pretty confused on how to handle click events (marker clicks) and also access the map state (current bounding box, current zoom level, etc). I'm getting errors such as I can't access the map state unless it's in a child component, or onclick handlers are not recognized, etc.

I want to eventually be able to do things such as load markers dynamically depend on zoom and bounding box, and click on a marker to zoom into it. This is probably due to me being an absolute beginning in react redux and hooks in general.

I'm not looking for anyone to just write the code for me, but if anyone can provide general guidance on how to accomplish these that would be super appreciated!

1
  • I am right there with you. This tool needs a major documentation overhaul in the repository. I am not unwilling to learn this stuff it's often a steep learning curve for newbies.
    – Greg Witt
    Commented Feb 3, 2023 at 19:28

2 Answers 2

3

To handle marker click events use eventHandlers prop and listen to click event inside on Markers comp like this:

const CustomMarkers = () => {
    const map = useMap();
    return markers.map((el, i) => (
      <Marker
        key={i}
        position={[el.latitude, el.longitude]}
        icon={icon}
        eventHandlers={{
          click: () => {
            console.log("marker clicked", el);
            console.log(map.getZoom());
          }
        }}
      />
    ));
  };

You can derive each marker element like this and take also information regarding map using useMap hook when you click on each marker.

To load markers dynamically depending on zoom level. An example could be this: You have a btn. When you click it you add dynamically a marker which has an event listener to zoom the map further. This will be triggered only if current map zoom level is 6 for example.

 function AddMarkerOnClick({ map }) {
        const onClick = () => {
          console.log(map.getZoom());
          if (map?.getZoom() === 6) {
            L.marker([39.77, -106.23], { icon })
              .addTo(map)
              .addEventListener("click", () => map.setZoom(4));
          }
        };
    
        return <button onClick={onClick}>Add marker on click</button>;
      }

...
return (
<>
      <AddMarkerOnClick map={map} />
      <MapContainer
        center={position}
      ...
</>
)

To be able to get the map reference you need your custom comps to be under MapContainer as children or get the map instance using whenCreated prop of MapContainer and then pass it on your custom comp.

Example Demo

1
  • 1
    thanks so much, this led to a much clearer understanding of react redux and solved my issue Commented Dec 7, 2020 at 4:58
0

in react-leaflet v3, if you want to use map an its properties in another app, or want to add something to the map from another component you can use this trick:

class MapComponent extends Component {
    constructor(props) {
    super(props);
    this.mapRef = React.createRef();
}
render() {
return (
   <div>    
       <MapContainer whenCreated={ mapInstance => { this.mapRef.current =mapInstance }}>
       </MapContainer>
       <AnotherComponent map = {this.mapRef}/>
   </div>}
}

class AnotherApp extends React.Component {
     //access the map with: 
     this.props.map
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.