Map with fully loaded tiles
Sometimes a grey map, sometimes half grey map, but when resizing the screen and/or panning it will load tiles.
Having trouble reproducing, I am copying the base example (https://jsfiddle.net/paul_lecam/q2v7t59h/) exactly, I am on React 15.2, I have the CSS in the head, and Leaflet 0.7.7, so I have no idea what the problem in because it seems like in isolation there are no issues, but when putting it in my application this occurs. Any ideas?
If you inline the height, does it work properly then?
<Map style={{height: "600px"}}> // plus whatever other props
// stuff
</Map>
I've been trying both an external stylesheet + className, inline styles like you suggested. It ends up looking like this
I have been seeing the same thing with my project. Any thoughts?
@mikeodell77 do you happen to be using Radium or any other inline style library?
Having the same issue, it seems the initial render of map renders 1 row of tiles. Any change to state or props which causes a re-render triggers the full map.
Same here.
i'm using css modules. I had a feeling that the containers aren't being styled fast enough before the map is rendering. This ticket may be related as well #40
I was able to get around this by using the extract text plugin for all of my styles rather than having inline styles loaded through webpack. The only caveat is that I can't use HMR for styles.
Hey Guys,
I'm also getting a completely grey map. This it the Map component:
import React from 'react'
import { Map, TileLayer } from 'react-leaflet'
class MapPage extends React.Component {
constructor (props, context) {
super(props, context)
this.state = {
lat: 51.505,
lng: -0.09,
zoom: 13
}
}
render () {
return (
<Map zoom={this.state.zoom}>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
</Map>
)
}
}
export default MapPage
I then import the Map component into another React component and just add it into the return () function as:
<MapPage />
The map shows up as completely grey, when I click and drag in the map, I get the following two errors:
leaflet-src.js:6697 Uncaught TypeError: Cannot read property 'subtract' of undefinedL.Draggable.L.Class.extend._onMove @ leaflet-src.js:6697handler @ leaflet-src.js:6380
22leaflet-src.js:6704 Uncaught TypeError: Cannot read property 'add' of undefinedL.Draggable.L.Class.extend._onMove @ leaflet-src.js:6704handler @ leaflet-src.js:6380
Also, the network traffic shows no tile request calls being made.
Currently using:
React - 0.14.8
react-leaflet - 0.11.1
material-ui - 0.15.0-alpha.2
babel - 6.7.2
Webpack - 1.9.11
Could it be just because I'm running it on a webpack-dev-server and not deployed onto a proper web server?
Managed to solve the issue. Problem was that I left out the center={_some position_} in the Map tag. I'm guessing center and zoom are required properties when instantiating a Map object in leaflet. Their doco shows this as the example:
// initialize the map on the "map" div with a given center and zoom
var map = L.map('map', {
center: [51.505, -0.09],
zoom: 13
});
Oh my sweet mercy. For me this issue was caused by
img {
max-height: 100%
}
I also had to pass in styles to the component setting its width and height. Further calling getLeafletElement().invalidateSize() in componentDidMount also did not work.
Closing as it seems due to bad configuration/environment setup, not an actual bug in the lib.
Please make sure you go through all the steps of Leaflet's getting started guide if you encounter this kind of problem.
This seems to be an issue with webpack style-loadernot operating well together with Leaflet as it loads styles after map initialization (see #46). Possible workaround is to set map container height with inline styles or use invalidateSize() method in componentDidMount handler, though this is not the option for functional React components.
In case it helps anyone, I got this error because of the tiling service I was using (hydaa). Switching to mapbox resolved the issue for me.
I don't think it's a conf issue. I tried to load with css and the issue is still happening!
best solution I found is to setTimeout. So problem is css modules are rendered after map it self and since leaflet depend on height it just renders first row since there is no in that moment css you set if you use css modules as well with webpack. So to go around that just set timeout with 0 miliseconds and it will be good. Code is here. Maybe this could be implemented in lib it self.
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Map, TileLayer } from 'react-leaflet';
import './mapView.scss';
class MapView extends Component {
constructor() {
super();
this.state = {
readyToRender: false,
};
}
render() {
const stamenTonerTiles =
'http://stamen-tiles-{s}.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png';
const stamenTonerAttr =
'Map tiles by <a href="http://stamen.com">Stamen Design</a>, <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>';
const mapCenter = [39.9528, -75.1638];
const zoomLevel = 12;
setTimeout(() => {
this.setState({ readyToRender: true });
}, 0);
return (
<div>
{this.state.readyToRender && (
<Map center={mapCenter} zoom={zoomLevel}>
<TileLayer attribution={stamenTonerAttr} url={stamenTonerTiles} />
</Map>
)}
</div>
);
}
}
export default MapView;
I also have this issue (with latest React, webpack, css modules, leaflet and react-leaflet). My workaround is calling invalidateSize:
componentDidMount() {
setTimeout(() => {
if (this.leafletMap.current) {
this.leafletMap.current.leafletElement.invalidateSize();
}
}, 100);
}
I also have this issue (with latest React, webpack, css modules, leaflet and react-leaflet). My workaround is calling
invalidateSize:componentDidMount() { setTimeout(() => { if (this.leafletMap.current) { this.leafletMap.current.leafletElement.invalidateSize(); } }, 100); }
Calling invalidateSize() within componentDidUpdate worked for me. A bit cleaner than using a timeout!
Same here. I'm using the latest version of create-react-app. Seems to be something related, because I've never had this issue on other environments.
@FabulousAid how did you referenced map within componentDidUpdate?
@rdgomt interesting I've noticed the same using [email protected] and [email protected]. I had to downgrade to 2.1.3 and the issue resolved. If you downgrade to 2.1.3 does it fix it for you too? Quite frustrating but not really sure where to start with fixing it...
Same here. I'm using the latest version of create-react-app. Seems to be something related, because I've never had this issue on other environments.
@FabulousAid how did you referenced map within componentDidUpdate?
@rdgomt I used a ref to access the map's functions. I ended up doing this:
```
class MapView extends React.Component {
mapRef = React.createRef();
componentDidUpdate() {
this.mapRef.current.leafletElement.invalidateSize();
}
render() {
return (
ref={this.mapRef}
/>
);
}
}```
It does not work for me. I already figured out that the problem is the center of map being top left of the leaflet which is why only small part of map loads. None of giving width/height, invalidating size, downgrading prop types and react scripts solved my problem yet.
Solved: My problem is using display: none on the map.
My problem was solved setting the zoom
solution using hooks (and mobx sotre) in FunctionComponent :
parent tabs Component
interface IProps {
defaultKey? :string
}
export const TabsTemplate: React.FC<IProps> = observer(({defaultKey="charts"}) => {
const [activeKey] = useState(defaultKey);
const store = useStore();
store.isReadyToRenderMap = false;
return (
<Tabs defaultActiveKey={activeKey} id="main-tabs"
onSelect={(activeKey: any) => {
if (activeKey === "map") {
//map is renderd only when tab is shown
store.isReadyToRenderMap = true;
}
}}
>
<Tab eventKey="charts" title={"Charts"}>
<GroupByGraphsPanel />
</Tab>
<Tab eventKey="map" title={"Map"}>
<MyMap />
</Tab>
</Tabs>
)
})
child map Component
const MyMap : FunctionComponent<IProps> = observer(() => {
const mapRef = useRef<any>();
const store = useStore();
const reactMapCenter = toJS(store.mapCenter);
const WRAPPER_STYLES = { height: '500px', width: '100vw', maxWidth: '100%' };
const didMountRef = useRef(false)
useEffect(() => {
if (didMountRef.current) {
if (mapRef.current) {
//mapRef.current = true - like componentDidUpdate
//this event is fierd when parent tab is shown - help render map
mapRef.current.leafletElement.invalidateSize(false);
}
}
else didMountRef.current = true
})
return (
<div>
<Map ref={mapRef}
center={reactMapCenter}
zoom={13}
style={WRAPPER_STYLES}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<AccidentsMarkers />
</Map>
{store.isReadyToRenderMap?"":""}
</div>
)
})
Most helpful comment
@rdgomt I used a ref to access the map's functions. I ended up doing this:
```
class MapView extends React.Component {
mapRef = React.createRef();
componentDidUpdate() {
this.mapRef.current.leafletElement.invalidateSize();
}
render() {
return (
ref={this.mapRef}
/>
);
}
}```