我在一个反应项目中工作,我想要实现的是一个带有谷歌地图的项目列表。我已经花了很多时间研究它,寻找最好的方法来做这件事,我找到了许多例子,但他们并没有真正表现出色。 另外我想要当你在列表中的项目上时,地图中相应项目的标记会改变颜色或类似的东西,所以我想将标记与列表中的项目同步。
这是我的Map组件,让您了解我目前正在使用的库:
import React from 'react';
import GoogleMaps from 'google-maps-api';
import MapConfig from 'config/maps.json';
import mapStyles from './map.styles';
const MapWithKey = GoogleMaps(MapConfig.API_KEY);
class Map extends React.Component {
render() {
const items = this.props.items;
MapWithKey().then(( maps ) => {
const map = new maps.Map(document.getElementById('js-map'), {
center: {lat: -34.397, lng: 150.644},
scrollwheel: false,
zoom: 8,
mapTypeControl: false,
streetViewControl: false
});
for ( let item of items ) {
new maps.Marker({
position: new maps.LatLng(item.latitude, item.longitude),
map: map
});
}
});
return(
<div style={mapStyles} id="js-map">{this.props.children}</div>
);
}
}
export default Map;
我注意到在开发过程中我无法在状态中添加标记,因为每次添加一个标记时,组件都会重新渲染。
您是否了解这样做的好方法并以良好的方式构建组件? 非常感谢帮助。
提前致谢。
答案 0 :(得分:3)
听起来像是shouldComponentUpdate
的工作。
此生命周期方法允许您决定每次更新状态或道具时是否应重新渲染组件。
shouldComponentUpdate() {
return false;
}
现在您可以安全地将标记存储在this.state
中,并使用命令式Maps API进行更新,而无需担心您的组件尝试重新渲染。
还值得一提的是shouldComponentUpdate
不会影响初始渲染,您仍然可以使用forceUpdate
强制更新它。
您可能还需要考虑重组您的组件以遵循一些最佳做法。您可以将ref
道具与回调一起使用,以获取对DOM元素的引用,而无需id
。
return(
<div style={mapStyles} ref={containerMounted}>{this.props.children}</div>
);
然后,您可以将初始化逻辑移动到新的containerMounted
方法中。
containerMounted(container) {
MapWithKey().then(( maps ) => {
const map = new maps.Map(container, {
// ...
});
// save a reference to map for later
this.setState({ map });
});
}
最后,当道具改变时,重新渲染标记很重要。以前我们可以在render
函数中完成此操作。您看到性能不佳的部分原因是因为您每次调用渲染时都在创建新标记。相反,你需要移动现有的。
// create the markers before initial render
componentWillMount() {
this.createMarkers(this.props.items);
}
// recreate the markers only when props changes
componentWillReceiveProps(nextProps) {
if(nextProps.items === this.props.items) return;
this.removeMarkers(this.state.markers);
this.createMarkers(nextProps.items);
}
// remove a list of markers from the map
removeMarkers(markers) {
markers.forEach(m => m.setMap(null));
}
// create a list of markers on the current map
createMarkers(items) {
const markers = items.map(item => {
return new maps.Marker({
position: new maps.LatLng(item.latitude, item.longitude),
map: this.state.map
});
});
}