2

我想MarkerCluster从上下文初始化一次创建带有传单地图的可重用组件,然后提供嵌套地图组件的更新。我需要将它不直接嵌入到MyMap组件中以执行动态操作react-router,但是嵌套标记MarkerCluster何时shouldComponentUpdate === false不会更新。我发现这个问题可能与问题有关,但在我的情况下我没有找到解决这个问题的方法。我仍然相信有比将 shouldComponentUpdate 设置为 true 更好的解决方案。你能解释一下我的两个例子之间的行为差​​异吗?或者,MarkerCluster以 React 方式构建没有上下文的可重用组件是否是一个更好的解决方案?

演示:

const React = window.React;
const { Map, TileLayer, Marker, MapLayer, PropTypes } = window.ReactLeaflet;
const { markerClusterGroup } = window.L;

class MarkerCluster extends MapLayer {
  static childContextTypes = {
    layerContainer: PropTypes.layerContainer
  };
  getChildContext () {
    return {
      layerContainer: this.leafletElement
    }
  }
  componentWillMount () {
    super.componentWillMount()
    this.leafletElement = markerClusterGroup()
  }
  shouldComponentUpdate () {
    return false
  }
  render () {
    console.log("update markers cluster")
    return <div style={{display: 'none'}}>{this.props.children}</div>
  }
}
class MapMarkers extends React.Component {
  constructor () {
    super()
	const initialState = [
  	  {position: [51.5, -0.1]},
  	  {position: [51.51, -0.1]},
  	  {position: [51.49, -0.05]},
	]
    this.state = {markers: initialState};
  }
  componentDidMount() {
    setInterval(this.addMarker.bind(this), 3000);
  }
  addMarker() {
    const lat = (Math.random() * (51.49 - 51.51) + 51.51);
    const lng = (Math.random() * (0.05 - 0.1) - 0.1);
    const marker = {position: [lat, lng]};
    this.setState({markers: this.state.markers.concat([marker])});
  }
  render() {
    console.log("update markers")
    const markers = this.state.markers.map((item, key) =>
      <Marker position={item.position} key={key} />
    );
    return <MarkerCluster>{markers}</MarkerCluster>;
  }
}
class MyMap extends React.Component {
  render() {
    return (
      <Map center={[51.50, -0.1]} zoom={13}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
        />
        {this.props.children}
      </Map>
    )
  }
}
class MainLayout extends React.Component {
  render() {
  	return (
      <MyMap>
        <MapMarkers />
      </MyMap>
    )
  }
}
window.ReactDOM.render(<MainLayout />, document.getElementById('container'));
.leaflet-container {
  height: 400px;
  width: 100%;
}
<link href="https://rawgit.com/Leaflet/Leaflet.markercluster/leaflet-0.7/dist/MarkerCluster.Default.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://rawgit.com/Leaflet/Leaflet.markercluster/leaflet-0.7/dist/leaflet.markercluster.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://npmcdn.com/react-leaflet@0.12.2/dist/react-leaflet.js"></script>
<div id="container"></div>

为什么下面的示例有效,而上面的示例无效?

const React = window.React;
const { Map, TileLayer, Marker, MapLayer, PropTypes } = window.ReactLeaflet;
const { markerClusterGroup } = window.L;

class MarkerCluster extends MapLayer {
  static childContextTypes = {
    layerContainer: PropTypes.layerContainer
  };
  getChildContext () {
    return {
      layerContainer: this.leafletElement
    }
  }
  componentWillMount () {
    super.componentWillMount()
    this.leafletElement = markerClusterGroup()
  }
  shouldComponentUpdate () {
    return false
  }
  render () {
    console.log('update markers cluster')
    return <div style={{display: 'none'}}>{this.props.children}</div>
  }
}
class MapMarkers extends React.Component {
  constructor () {
    super()
	const initialState = [
  	  {position: [51.5, -0.1]},
  	  {position: [51.51, -0.1]},
  	  {position: [51.49, -0.05]},
	]
    this.state = {markers: initialState};
  }
  componentDidMount() {
    setInterval(this.addMarker.bind(this), 3000);
  }
  addMarker() {
    const lat = (Math.random() * (51.49 - 51.51) + 51.51);
    const lng = (Math.random() * (0.05 - 0.1) - 0.1);
    const marker = {position: [lat, lng]};
    this.setState({markers: this.state.markers.concat([marker])});
  }
  render() {
    console.log('update markers')
    const markers = this.state.markers.map((item, key) =>
      <Marker position={item.position} key={key} />
    );
    return <div>{markers}</div>;
  }
}
class MyMap extends React.Component {
  render() {
    return (
      <Map center={[51.50, -0.1]} zoom={13}>
        <TileLayer
          attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
          url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
        />
        <MarkerCluster><MapMarkers /></MarkerCluster>
      </Map>
    )
  }
}
class MainLayout extends React.Component {
  render() {
  	return (
      <MyMap />
    )
  }
}
window.ReactDOM.render(<MainLayout />, document.getElementById('container'));
.leaflet-container {
  height: 400px;
  width: 100%;
}
<link href="https://rawgit.com/Leaflet/Leaflet.markercluster/leaflet-0.7/dist/MarkerCluster.Default.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script>
<script src="https://rawgit.com/Leaflet/Leaflet.markercluster/leaflet-0.7/dist/leaflet.markercluster.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://npmcdn.com/react-leaflet@0.12.2/dist/react-leaflet.js"></script>
<div id="container"></div>

4

2 回答 2

0

检查react-leaflet-markercluster的实现

这是用于聚类标记的最小且轻量级的包装器。

来源:src/react-leaflet-markercluster.js

1) Wrapper 扩展了 react-leaflet LayerGroup:

import {LayerGroup} from 'react-leaflet';

export default class MarkerClusterGroup extends LayerGroup {
    ...

2)创建新的markerClusterGroup,所有标记都将聚集的组:

import 'leaflet.markercluster';

let markerClusterGroup = L.markerClusterGroup(this.props.options);

3)通过layerContainer将该markerClusterGroup作为图层添加到地图中(layerContainer是可用的,因为MarkerClusterGroup组件扩展了react-leaflet LayerGroup)

this.layerContainer.addLayer(markerClusterGroup);
于 2017-03-14T11:34:04.230 回答
0

我不知道你为什么要那样做。您应该首先了解 react 是如何工作的,以及它是如何进行协调过程的。

看看这里,这解释了这个过程: https ://facebook.github.io/react/docs/reconciliation.html

在这里您可以阅读有关高级 prefomance 的信息,包括有关 shouldComponentUpdate 以及如何正确使用它的广泛解释:

https://facebook.github.io/react/docs/advanced-performance.html

希望在你读完这篇文章之后,你会明白为什么你想要的东西是不可能的。无论如何,你永远不应该实现 shouldComponentUpdate 来返回 false,因为它会跳过协调过程中的所有嵌套组件。

于 2016-09-19T03:42:28.607 回答