在反应传单地图上构建很多标记太慢

时间:2018-10-03 05:36:12

标签: reactjs react-leaflet

我有一个要显示在Leaflet地图上的4360个地理标记的数据集。 CircleMarker可以正常工作,并且构造的地图的性能还可以。但是,构建地图会花费太多时间(大约20秒)。没有反应,只需几分之一秒即可构建标记。有一些性能提示或技巧可以用来使其更快地构建地图吗?

import * as React from 'react';
import { Component } from 'react';
import { LatLng } from 'leaflet';
import { Map, TileLayer, CircleMarker, Popup } from 'react-leaflet';

export default class Editor extends Component {
    state = {
        lat: 51.505,
        lng: -0.09,
        zoom: 13,
        markers : [ ]
    }

    componentDidMount() {
        // data.csv contains several thousands of items
        fetch('data.csv')
            .then(res => res.json())
            .then(data => this.setState({ markers: data.items.map(v => new LatLng(v.lat, v.lng)) }));
    }

    render() {
        const markers = this.state.markers.map((v, i) =>
            <CircleMarker key={i} center={v} radius={3} />);
        return (
            <Map center={new LatLng(51.505, -0.09)} zoom={this.state.zoom}>
                <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
                {markers}
            </Map>
        )
    }
}

直接DOM操作只需几分之一秒即可完成:

export default class ItemsMap extends React.Component {
  state = { items : [ ] };
  map : L.Map;

  componentDidUpdate(prevProps : any, prevState : any) {
    this.renderItems(this.state.items);
  }

  componentDidMount() {
    const node : any = ReactDOM.findDOMNode(this);
    this.map = L.map(node).setView([51.505, -0.09], 13);
    L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18 }).addTo(this.map);

    fetch('data.csv')
      .then(res => res.json())
      .then(data => this.setState({ items: data.items.map(v => new LatLng(v.lat, v.lng)) }));
  }

  renderItems(items : Array<any>) {        
    items.forEach(item => {
      L.circleMarker(
        [ item.lat, item.lng ],
        { radius : 3 }
      ).addTo(this.map);
    });
  }

  render() {
    return (
      <div id="mapid" style={{ height: '100%' }} />
    );
  }
}

3 个答案:

答案 0 :(得分:0)

要考虑的一种技术是在给定地图边界内仅渲染标记的子集,它可以大大减少重新渲染组件所需的时间以及DOM的数量创建的节点:

 componentDidMount() {
    fetch('data.csv')
   .then(res => res.json())
   .then(data => {
       this.allMarkers = data.items.map(v => new LatLng(v.lat, v.lng));
       displayMarkers();
    });
 }

其中

displayMarkers() {
   const map = this.mapRef.current.leafletElement;
   const markers = this.allMarkers.filter(m =>
      map.getBounds().contains(m)
   );

   this.setState({
       markers: markers
   });
}

Demo

另一种优化方法(特定于传单)是将preferCanvas设置为true 在画布上而不是SVG上渲染标记

  

是否应在Canvas渲染器上渲染路径。默认情况下,所有   路径是在SVG渲染器中渲染的。

<Map
    preferCanvas={true}
    center={new LatLng(51.505, -0.09)}
    zoom={this.state.zoom}
  >
    ... 
  </Map>

following demo演示了如何通过react-leaflet

渲染 20k 标记

答案 1 :(得分:0)

我是通过覆盖shouldComponentUpdate lifeCycle方法解决问题的,像地图这样的组件的问题是它们通常太重了。因此,如果您有很多标记和地图lee [pm rerendering,则应重写shouldComponent生命周期方法。这样,您可以确保仅在必要的属性发生更改时才重新渲染地图(昂贵的操作)。这会有所帮助。

shouldComponentUpdate(prevProps) {
 return !areEqual(this.props, prevProps);
}

答案 2 :(得分:0)

我的问题稍有不同,就是在可接受的时间内渲染了点,但是平移和缩放速度非常慢。我的本机javascript应用程序工作正常。这里的建议都没有帮助。

Why is Leaflet so slow at pan and zoom inside React?

我通过将本机javascript地图应用程序放在react页面上的iframe中解决了该问题。这不是一个理想的解决方案,我希望有一个更好的解决方案,但是我的猜测是,它将需要更新传单或做出反应。