I'm trying to add markers when a user clicks on a certain Geojson feature. I'm new to react and react-leaflet and am trying to use the useState hook to accomplish this task. I've been stuck a couple of days on this issue.
Here is my App.js. I import data, create a state variable and setter for my markers, and pass those items to my components <MyData/>
and <MyMarkers/>
.
import "./styles.css";
import React, { useState } from 'react'
import {MapContainer, TileLayer} from 'react-leaflet'
import L from 'leaflet'
import someData from './data.geojson'
import MyData from './components/MyData.js'
import MyMarkers from './components/MyMarkers.js'
// import bugged marker
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';
// set the default icon
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [2, -40],
});
L.Marker.prototype.options.icon = DefaultIcon;
export default function App() {
// create state variable and setter for the markers
let [markers, setMarkers] = useState([])
// import geojson data
let data= JSON.parse(someData)
return (
<>
<MapContainer
doubleClickZoom={false}
id="mapId"
zoom={14}
center={[37.37569444, -91.5528056]}
>
<TileLayer
url="https://server.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Light_Gray_Base/MapServer/tile/{z}/{y}/{x}"
attribution="Tiles © Esri — Sources: GEBCO, NOAA, CHS, OSU, UNH, CSUMB, National Geographic, DeLorme, NAVTEQ, and Esri"
/>
<MyData data={data} markers = {markers} setMarkers ={setMarkers}/>
{markers.length >0 && <MyMarkers markers={markers}/>}
</MapContainer>
</>
);
}
Here is my MyData component which displays the geojson data. It receives geojson data, an array of objects, and a function to set the state of the markers.
import React from 'react';
import { GeoJSON } from 'react-leaflet';
function MyData ({data, markers, setMarkers}) {
// data not null, return the geojson component
if (data) {
return <GeoJSON pathOptions={ { color: "red" } } data={data} eventHandlers={{
// click handler for geojson component
click: (e) => {
// push the latlng object to the markers array
markers.push(e.latlng)
// set the state using the setter...why does this not render markers?
setMarkers(markers)
}
}} />;
} else {
return null;
}
};
export default MyData
Here is my MyMarkers component which iterates through the array of markers which I pass it as a prop ideally creating Marker components at each position. (this doesn't work)
import React from 'react';
import { Marker } from 'react-leaflet';
function MyMarkers ({markers}) {
// check length of the markers
if (markers.length > 0){
// iterate through the array of markers creating a marker with unique id at given latlngs
markers.map((position, id) => {
return <Marker key={id} position={position}/>
})
} else {
return null;
}
};
export default MyMarkers
I'm able to draw my geojson data on the map but am unable to get markers to show up on click of my <MyData/>
component. What am I missing here? My understanding is that when trying to update state of sibling components ( <MyData/>
and <MyMarkers/>
) the state needs to be lifted to a common ancestor (<App/>
in this case) which is what I have attempted to do. How can I successfully update the state onclick from inside <MyData/>
to render the markers?
Here is a sandbox of the issue and code above as well.
Thanks