I've been working on a map component that renders points of results that stream in from search. I have gotten most of it working, until I began passing props in for the return statement. I'm using my own component, not react-leaflet's . I've noticed if I use <Map ... />
and render with props.locations.map( ...
it works fine. If I reference my map = L.map(...)
with <map ref={map} >
and try to render <Marker .../>
with props, it breaks as soon as it attempts to create the layer and add it to the map.
The component's JS File is as follows:
import React, {Component, useEffect, useState} from "react";
import {Map, Marker, Popup, TileLayer} from "react-leaflet";
import * as L from 'leaflet'
import 'leaflet-draw'
import 'leaflet/dist/leaflet.css';
import 'leaflet-easybutton'
import 'leaflet-easybutton/src/easy-button.css';
import Style from './MapSearch.css'
import icon from 'leaflet/dist/images/marker-icon.png';
import iconShadow from 'leaflet/dist/images/marker-shadow.png';
const MapSearch = (props) => {
const [layers,setLayers] = useState([]);
const [results,setResults] = useState([]); //Not used
const [map,setMap]=useState({});
useEffect(()=> {
console.log('mounted');
let map = L.map('mapsearch').setView([51.505, -0.09], 6);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
}).addTo(map);
/** Add the feature group and draw control to the map. */
let drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
const drawControl = new L.Control.Draw({
position: 'topright',
draw: {
polyline: false,
rectangle: false,
circlemarker: false,
polygon: false,
circle: true,
marker: true,
},
edit: {
featureGroup: drawnItems,
remove: true,
},
});
map.addControl(drawControl);
/** On shape drawn, add the new layer to the map. */
map.on(L.Draw.Event.CREATED, (e) => {
const type = e.layerType;
const layer = e.layer;
if (type === 'marker') {
layer.bindPopup('popup');
}
console.log('LAYER ADDED:', layer);
drawnItems.addLayer(layer);
// this.setState({layers: drawnItems.getLayers()});
let testArr=drawnItems.getLayers(); /**BROKEN SECTIoN TODO */
// setLayers(layers=> [...layers,layer]);
//console.log({layers});
console.log('GEO JSON', drawnItems.toGeoJSON());
console.log(' LAYERS', drawnItems.getLayers());
});
L.easyButton('fa-search', () => {
isWithinPolygon(props); //Removed because not relevant to question
}, 'Search Current Results within drawn layers', {position: 'topright'}).addTo(map);
map.on(L.Draw.Event.EDITED, (e) => {
const layers = e.layers;
let countOfEditedLayers = 0;
console.log('LAYER EDITED:', layers);
layers.eachLayer((layer) => {
countOfEditedLayers++;
});
});
setMap(map); //hook to set map
//this.setState({map: map});
console.log("map:",{map}); }
,[]);
return (
<div id='mapsearch'>
<map center={[0, 0]} zoom={0}>
{props.locations.map(marker => (
(marker.props.isLocationEnabled === true ?
(marker.props.isMarkerClicked === true ?
(<Marker
key={marker.props.id}
position={ [
marker.props.lat,
marker.props.long
]}
opacity= '1.0'>
<Popup>
<b>Media ID:</b> {marker.props.values.mediaId}
<br/>
<b>Created Date:</b> {marker.props.values.createdDate}
<br/>
<b>Media URL:</b> <button onClick={()=> window.open(marker.props.values.mediaURL)}>Link</button>
</Popup>
</Marker>) :
(<Marker
key={marker.props.id}
position={ [
marker.props.lat,
marker.props.long
]}
opacity= '0.5'>
<Popup>
<b>Media ID:</b> {marker.props.values.mediaId}
<br/>
<b>Created Date:</b> {marker.props.values.createdDate}
<br/>
<b>Media URL:</b> <button onClick={()=> window.open(marker.props.values.mediaURL)}>Link</button>
</Popup>
</Marker>)
) : (<div></div>)
)
))}
</map>
</div>
);
};
export default MapSearch;
Index:
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Media Search UI"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<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>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script src="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.js"></script>
<link href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
Pretty stumped on this. Why can it map & render <Markers>
when using <Map>
but not my <map />
?
EDIT: Screenshot of using <Map ref={map} ... />
. Adds duplicate layers, making 80% of map not draggable.
So as I mentioned in the comments you should use
react'leaflet
's Map and use a ref to add any plugin you wish using native leaflet code.and then on useEffect when the component mounts take the map reference and use it accordingly to initialise any other leaflet plugin:
Demo