Why I am getting 'Map' is not exported from 'react-leaflet'? - reactjs

Why I am getting:
./src/components/mapComponent/MapView.jsx
Attempted import error: 'Map' is not exported from 'react-leaflet'.
I am importing this in the component:
import React, { Component } from "react";
import { Map, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
This is confusing me where to look as all looks to be correct in code....

Try with MapContainer component.
The MapContainer component is responsible for creating the Leaflet Map
instance and providing it to its child components, using a React
Context.
When creating a MapContainer element, its props are used as options to
create the Map instance.
Now you have to import MapContainer.
import { MapContainer, TileLayer, Marker } from 'react-leaflet';
<MapContainer
className="markercluster-map"
center={[51.0, 19.0]}
zoom={4}
maxZoom={18}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
</MapContainer>

Change Map to MapContainer.
import { MapContainer, TileLayer } from "react-leaflet";

This problem is occurring in the older version try using "react-leaflet": "^3.2.1", "leaflet": "^1.7.1", and it would resolve, if you are using react 17 and upper .
https://codesandbox.io/s/cluster-mapping-leaflet-9bkes
import { TileLayer, Tooltip, Marker, MapContainer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import MarkerClusterGroup from "react-leaflet-markercluster";
import { customMarker } from "./constants";
import L from "leaflet";
const Cluster = () => {
let data = {
minLat: -6.1751,
maxLat: 55.7558,
minLong: 37.6173,
maxLong: 139.6917
};
const centerLat = (data.minLat + data.maxLat) / 2;
var distanceLat = data.maxLat - data.minLat;
var bufferLat = distanceLat * 0.05;
const centerLong = (data.minLong + data.maxLong) / 2;
var distanceLong = data.maxLong - data.minLong;
var bufferLong = distanceLong * 0.05;
const zoom = 4;
const cities = [
{ position: [22.583261, 88.412796], text: "A" },
{ position: [22.58289, 88.41366], text: "B" }
];
return (
<MapContainer
style={{ height: "480px", width: "100%" }}
zoom={zoom}
center={[centerLat, centerLong]}
bounds={[
[data.minLat - bufferLat, data.minLong - bufferLong],
[data.maxLat + bufferLat, data.maxLong + bufferLong]
]}
scrollWheelZoom={true}
>
<TileLayer url="http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<MarkerClusterGroup>
{cities?.map((mark, i) => (
<Marker
style={{ color: "red" }}
key={i}
position={mark?.position}
icon={customMarker}
>
<Tooltip direction="top" offset={[10, 0]}>
<span style={{ fontSize: 14, fontWeight: "bold" }}>
{mark?.text}
</span>
</Tooltip>
</Marker>
))}
</MarkerClusterGroup>
</MapContainer>
);
};
export default Cluster;
export const customMarker = new L.Icon({
iconUrl: "https://unpkg.com/leaflet#1.5.1/dist/images/marker-icon.png",
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40]
});

You should use import {MapContainer} from "react-leaflet" instead of Map and before doing that install both react-leaflet and leaflet by
$ npm i leaflet react-leaflet
Hope this solve your problem

This problem is occurring in the newer version try using "react-leaflet": "^2.8.0","leaflet": "^1.7.1"and it would resolve

Related

Create a choropleth map of all cities in world in react js

I am trying to make a choropleth map of the world but with city level detail where a region of world or country explored by a user gets a color.
So far I am able to find solutions to create a world map with country level shapes or polygons in geojson. This is what I currently have.
What I wish to achieve is when I zoom in should be able to see similar output but with city or state or province level details.
What I have is has been built using react-leaflet and geojson file that contains boundaries of all the countries in the world.
I've been looking all over the internet for city level geojson or a map library that can help me but no luck so far. Here is the code
import { MapContainer, Marker, GeoJSON, useMap, TileLayer } from 'react-leaflet';
import React, { useRef, useEffect, useState, useLayoutEffect } from 'react';
import mapData from './test.json';
const imagePin = '/images/map-pin.png';
import L from 'leaflet';
import LayersSelector from 'components/atoms/LeafletMap/LayersSelector';
import LeafletMapUtils from './logic';
import { MapView } from './types';
type IProps = {
pins: any;
center?: [number, number];
zoom?: number;
};
const Map = ({
pins = [],
center = [0.9137839459007647, 1.3199101440788825],
zoom = 2.3
}: IProps) => {
const mapRef = useRef();
const [mapView, setMapView] = useState(MapView.SATELLITE);
return (
<div className="h-full w-full">
<MapContainer
ref={mapRef}
center={[0.9137839459007647, 1.3199101440788825]}
zoom={zoom}
zoomSnap={0.1}
zoomControl={false}
// className={styles.leafletContainer}
scrollWheelZoom={true}
style={{ height: '100%', width: '100%' }}
// maxBounds={bounds}
// crs={L.CRS.Simple}
>
{mapView === MapView.JINNI && (
<GeoJSON
style={{
fillColor: '#EBEBEB',
fillOpacity: 1,
// color: '#717171',
weight: 0.5,
stroke: true,
color: '#000000'
// border: '1px solid #dddd'
}}
onEachFeature={(country, layer) =>
LeafletMapUtils.onEachCountry(country, layer)
}
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
data={mapData}
/>
)}
</MapContainer>
</div>
);
};
export default Map;
I found a Geojson file on the internet with polygons on all countries: https://datahub.io/core/geo-countries. I use Leaflet.js:
geojsondata = ... // the geojson data
readfromjson = L.geoJSON(geojsondata).addTo(map)

Uncaught Error: Map container is already initialized

I am using React JS for making a webpage. My aim is to display a map on the front end. I am using the react-leaflet npm package for the same. However, I am getting the below error:
Error...
"Uncaught Error: Map container is already initialized.
at NewClass._initContainer (Map.js:1105:1)
at NewClass.initialize (Map.js:136:1)
at new NewClass (Class.js:22:1)
at MapContainer.js:10:1
at commitHookEffectListMount (react-dom.development.js:22969:1)
at invokePassiveEffectMountInDEV (react-dom.development.js:24948:1)
at invokeEffectsInDev (react-dom.development.js:27142:1)
at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27121:1)
at flushPassiveEffectsImpl (react-dom.development.js:26865:1)
at flushPassiveEffects (react-dom.development.js:26801:1)"
Following is my code:
import React from 'react'
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
const Map = () => {
return (
<MapContainer center={[51.505, -0.09]} zoom={13}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[51.505, -0.09]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
)
}
It seems an important question to me. Hence, answering here for sake of completeness. This is based on this link shared by #Satya S in the comments. React leaflet v3 won't work with reactJS v18 (as of the time of writing this response, things may change later. Use this link to verify), at least when using concurrent mode.
Please try version 4 alpha of React leaflet that targets version 18 of reactJS.
This works for me. Hope it could help.
import React, { useEffect } from "react";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import icon from "leaflet/dist/images/marker-icon.png";
import iconShadow from "leaflet/dist/images/marker-shadow.png";
let DefaultIcon = L.icon({
iconUrl: icon,
shadowUrl: iconShadow,
});
export default function Map() {
useEffect(() => {
var container = L.DomUtil.get("map");
if (container != null) {
container._leaflet_id = null;
}
var map = L.map("map").setView([51.505, -0.09], 13);
L.tileLayer(
"https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}",
{
attribution:
'Map data © OpenStreetMap contributors, Imagery © Mapbox',
maxZoom: 18,
id: "mapbox/streets-v11",
tileSize: 512,
zoomOffset: -1,
accessToken:
"pk.eyJ1IjoidGFyLWhlbCIsImEiOiJjbDJnYWRieGMwMTlrM2luenIzMzZwbGJ2In0.RQRMAJqClc4qoNwROT8Umg",
}
).addTo(map);
L.Marker.prototype.options.icon = DefaultIcon;
var marker = L.marker([51.5, -0.09]).addTo(map);
marker.bindPopup("<b>Hello world!</b><br>I am a popup.").openPopup();
}, []);
return <div id="map" style={{ height: "100vh" }}></div>;
}
Don't forget to insert these CSS and JS to your index.html head:
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.8.0/dist/leaflet.css" integrity="sha512-hoalWLoI8r4UszCkZ5kL8vayOGVae1oxXe/2A4AO6J9+580uKHDO3JdHb7NzwwzK5xr/Fs0W40kiNHxM9vyTtQ==" crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.8.0/dist/leaflet.js" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" crossorigin=""></script>

TypeError: Cannot read properties of undefined (reading 'latLng')

Now, I am trying to create an app with react and I am using Google Map API for the project.
I got this error but I have no idea why this occurs.
If anyone knows any clues please let me now.
import React from 'react';
import GoogleMapReact from 'google-map-react';
import { Paper, Typography, useMediaQuery } from '#material-ui/core';
import useStyles from './styles'
const Map = () => {
const classes = useStyles()
const isMobile = useMediaQuery('(min-width:600px)')
const coordinates = { lat: 0, lng: 0 }
return (
<div className={classes.mapContainer}>
<GoogleMapReact>
bootstrapURLKeys={{ key: 'AaosjbnsajsnbjIUYIkbbaskjbd' }}
defaultCenter={coordinates}
center={coordinates}
defaultZoom={14}
margin={[50, 50, 50, 50]}
options={''}
onChange={''}
onChildClick={''}
</GoogleMapReact>
</div>
)
}
export default Map;
a simple > is misplaced. Instead of passing props , unintentionally, you are passing children to the component.
<GoogleMapReact>
bootstrapURLKeys={{ key: 'AaosjbnsajsnbjIUYIkbbaskjbd' }}
defaultCenter={coordinates}
center={coordinates}
defaultZoom={14}
margin={[50, 50, 50, 50]}
options={''}
onChange={''}
onChildClick={''}
</GoogleMapReact>
change it to this:
<GoogleMapReact
bootstrapURLKeys={{ key: 'AaosjbnsajsnbjIUYIkbbaskjbd' }}
defaultCenter={coordinates}
center={coordinates}
defaultZoom={14}
margin={[50, 50, 50, 50]}
options={''}
onChange={''}
onChildClick={''}>
</GoogleMapReact>
Look at GoogleMapReact props
<GoogleMapReact ...props></GoogleMapReact>

using react-leaflet-editable with react-leaflet 2.8.0

I am integrating/including react-leaflet-editable to my existing project which relies 100% on react-leaflet v2.8.0. I am not able to upgrade at the moment as it requires too much changes to the entire project. Something we cannot afford at the moment. (Why change everything for one when one can change for all. Yes we will probably do this someday but not now)
so here is the code below. it works perfectly with react-leaflet v.3.x but the moment I siwtch to `version 2.8.0' it seizes to work.
What I have tried; Map is renamed to MapContainer in 3.x so I change that but the problem then becomes the whenCreated={setMap} parameter. I need a way to get that linked to the ReactLeafletEditable. or at least I think that is the problem.
I hope I have explained well. the code and link is below.
import React, { useRef } from "react";
import L, { Icon } from "leaflet";
import "leaflet-editable";
import ReactLeafletEditable from "react-leaflet-editable";
import {
MapContainer,
TileLayer,
LayersControl,
LayerGroup
} from "react-leaflet";
import "leaflet/dist/leaflet.css";
function Demo() {
const editRef = useRef();
const [map, setMap] = React.useState();
const editPolygon = () => {
editRef.current.startPolygon();
};
return (
<ReactLeafletEditable ref={editRef} map={map}>
<button onClick={editPolygon} className="editable-btn">
Create Polygon
</button>
<MapContainer
style={{
height: "700px",
backgroundColor: "",
flexGrow: "1",
cursor: `10`
}}
editable={true}
zoom={4}
maxZoom={18}
center={[35, 105]}
whenCreated={setMap}
>
<LayerGroup>
<TileLayer
attribution='&copy OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<TileLayer url="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" />
</LayerGroup>
</MapContainer>
</ReactLeafletEditable>
);
}
export default Demo;
Link to project in 3.0: https://codesandbox.io/s/react-leaflet-editable-z7tnq?file=/src/App.js
link to react-leaflet-editable : https://www.npmjs.com/package/react-leaflet-editable
PS: You can just switch the react-leaflet version on the side to 2.8.0 see the behavior.
Thank you for all support
Use a ref in combination with a useEffect to get the map instance in react-leaflet v.2.x. With that way you imitate what whenCreated does in version 3.x
const [map, setMap] = React.useState();
const mapRef = useRef();
useEffect(() => {
if (!mapRef.current) return;
setMap(mapRef.current.leafletElement);
}, []);
<ReactLeafletEditable ref={editRef} map={map}>
<button onClick={editPolygon} className="editable-btn">
Create Polygon
</button>
<Map
style={{
height: "700px",
backgroundColor: "",
flexGrow: "1",
cursor: `10`
}}
ref={mapRef}
...
Demo

ReacMapboxGl Marker doesn't show on map

import ReactMapboxGl, { Marker } from "react-mapbox-gl";
import React from "react";
const Map = ReactMapboxGl({
accessToken: process.env.REACT_APP_MAPBOX_TOKEN,
});
export default function App() {
return (
<Map
style="mapbox://styles/mapbox/streets-v9"
containerStyle={{
height: "100vh",
width: "100vw",
}}
center={[-74.006, 40.7128]}
>
<Marker coordinates={[-74.006, 40.7128]}>
<div>IAM HEEEEEEEEEEEEEEEEERE</div>
</Marker>
</Map>
);
}
This is a basic map showing using mapbox-react-gl.
There is no bug showing in console log but I can not see the marker on the map.
I think you didn't set the coordinates correctly (latitude, longitude)
They should be, based in your example [40.7128 -74.006]

Resources