2016-09-18 8 views
2

Я хотел бы создать многоразовый компонент MarkerCluster с карточкой листовки из контекста, инициализировать его один раз, а затем предоставлять обновления на вложенных компонентах карты. Мне нужно встроить его непосредственно в компонент MyMap для выполнения динамических действий с react-router, но когда MarkerCluster имеет shouldComponentUpdate === false, тогда вложенные маркеры не будут обновляться. Я обнаружил, что эта проблема может быть связана с issue, но я не нашел, как это сделать в моем случае. Я все еще верю, что есть лучшее решение, чем просто установить toComponentUpdate в 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() 
 
\t const initialState = [ 
 
    \t {position: [51.5, -0.1]}, 
 
    \t {position: [51.51, -0.1]}, 
 
    \t {position: [51.49, -0.05]}, 
 
\t ] 
 
    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() { 
 
    \t 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/[email protected]/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() 
 
\t const initialState = [ 
 
    \t {position: [51.5, -0.1]}, 
 
    \t {position: [51.51, -0.1]}, 
 
    \t {position: [51.49, -0.05]}, 
 
\t ] 
 
    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() { 
 
    \t 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/[email protected]/dist/react-leaflet.js"></script> 
 
<div id="container"></div>

+2

Это не то, для чего используется компонентShouldUpdate. Вы сказали, что он не обновляется, и теперь он не обновляется. Если вы хотите, чтобы он обновлялся, тогда не устанавливайте этот крючок таким образом. – gravityplanx

+0

Итак, почему второй пример работает? – luzny

+0

It ** - ** рабочий.Вы сказали, что не обновлять, а не обновлять. Если вы хотите его обновить, не устанавливайте эту функцию для возврата 'false'. – gravityplanx

ответ

0

Я не знаю, почему вы могли бы сделать это. Сначала вы должны понять, как реагирует работа, и как он выполняет процесс согласования.

Посмотрите здесь, это объясняет процесс: https://facebook.github.io/react/docs/reconciliation.html

И здесь вы можете прочитать о передовых prefomance, включая широкое разъяснение о shouldComponentUpdate и как правильно его использовать:

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

Надеюсь, после того, как вы прочитаете это, вы поймете, почему то, что вы хотите, невозможно. В любом случае, вы никогда не должны внедрять shouldComponentUpdate для возврата false, поскольку он будет пропускать все вложенные компоненты в процессе согласования.

0

Проверить выполнение react-leaflet-markercluster

Это минимальная и легкая обертка для маркеров кластеризации.

Источник: src/react-leaflet-markercluster.js

1) Упаковочный расширяет реагировать-листовку 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) Добавление этого маркераClusterGroup к карте в качестве слоя через layerContainer (layerContainer доступен, поскольку компонент MarkerClusterGroup, расширяющий реакционную буклету LayerGroup)

this.layerContainer.addLayer(markerClusterGroup);