Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Leaflet: Is there a way to make an onClick method that adds a marker and also updates the state with that markers' location? (Beginner React)

I have seen solutions where they use the Map component, but I read that this has been updated to the MapContainer which does not have an onClick Method. Right now, my code (below) allows me to add a marker when I click anywhere on the map. As my title states, how would I store the new marker in some kind of usable variable. My end goal is to store new markers in MongoDB. Thanks in advance.

import React, { Component } from 'react';
import {
  MapContainer,
  TileLayer,
  MapConsumer,
} from "react-leaflet";
import Leaflet from "leaflet";
import { connect } from 'react-redux';

import { Icon } from "../Leaflet/Configurations";
import NavBar from '../components/NavBar';
import Footer from '../components/Footer';
import { registerHouse } from '../actions/houseActions';
import { clearErrors } from "../actions/errorActions";
import "leaflet/dist/leaflet.css";

class MyMap extends Component{
    constructor(props){
        super(props);
        this.state = {
            markers: [[40.7, -74]],
            data: []
        };
        this.addMarker = this.addMarker.bind(this);
    }
    
    render(){
        return(
            <div>
                <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css"
   integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
   crossOrigin=""/>
                <script src="https://unpkg.com/[email protected]/dist/leaflet.js"
            integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
            crossOrigin=""></script>
                <NavBar/>
                {/* <MapContainer className="Map" center={{ lat: 40.7 , lng: -74 }} zoom={15} scrollWheelZoom={false}>
                    <TileLayer
                        attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
                        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                    />
                    <MapConsumer>
                        {(map) => {
                            console.log("map center:", map.getCenter());
                            map.on("click", function (e) {
                                const { lat, lng } = e.latlng;
                                Leaflet.marker([lat, lng], { Icon }).addTo(map);
                                let tmp = this.state.data;
                                tmp.append([lat,lng]);
                                this.setState({data:tmp});
                            });
                            return null;
                        }}
                    </MapConsumer>
                </MapContainer> */}
                <Footer/>
            </div>
        )
    }
}


const mapStateToProps =  state => ({
    isAuthenticated: state.auth.isAuthenticated,
    error: state.error
});

export default connect(mapStateToProps, { registerHouse, clearErrors })(MyMap);
like image 714
ENDGAMEPROPHECY Avatar asked Nov 19 '25 04:11

ENDGAMEPROPHECY


1 Answers

I am not sure this part of your code works:

let tmp = this.state.data;
tmp.append([lat,lng]);
this.setState({data:tmp});

why? Because this.state is undefined inside map.on('click) block scope. It loses its reference there.

So what you could do is create a custom child component of MapContainer and take advantage of a concept in react called raising an event from the child to the parent component. The parent will send an event to the child and the latter calls that function when something happens.

function MyComponent({ saveMarkers }) {
  const map = useMapEvents({
    click: (e) => {
      const { lat, lng } = e.latlng;
      L.marker([lat, lng], { icon }).addTo(map);
      saveMarkers([lat, lng]);
    }
  });
  return null;
}

and in your MyMap comp define the event

saveMarkers = (newMarkerCoords) => {
    const data = [...this.state.data, newMarkerCoords];
    this.setState((prevState) => ({ ...prevState, data }));
};

which will be passed as a prop to the custom comp:

 <MapContainer
   ...
  <MyComponent saveMarkers={this.saveMarkers} />
 </MapContainer>

Demo

like image 151
kboul Avatar answered Nov 21 '25 16:11

kboul



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!