为啥要在标记点击事件上重新渲染地图?

Posted

技术标签:

【中文标题】为啥要在标记点击事件上重新渲染地图?【英文标题】:Why map re rendering on marker click event?为什么要在标记点击事件上重新渲染地图? 【发布时间】:2019-10-03 08:18:55 【问题描述】:

我有带有集群的多个标记的谷歌地图。单击标记时,我会显示信息窗口,但是当我单击标记时,整个地图标记和集群都会重新渲染,这会使页面变慢且令人讨厌。

以下是我的代码:

import React,  Component  from "react";
import axios from "axios";
import  compose, withProps, withHandlers, withStateHandlers  from "recompose";
import 
  withScriptjs,
  withGoogleMap,
  GoogleMap,
  Marker,
  InfoWindow
 from "react-google-maps";
const 
  MarkerClusterer
 = require("react-google-maps/lib/components/addons/MarkerClusterer");

const MapWithAMarkerClusterer = compose(
  withProps(
    googleMapURL:
      "https://maps.googleapis.com/maps/api/js?key=API&v=3.exp&libraries=geometry,drawing,places",
    loadingElement: <div style= height: `100%`  />,
    containerElement: <div style= height: `90vh`  />,
    mapElement: <div style= height: `100%`  />
  ),
  withStateHandlers(
     InfoWindowobject: null ,
    
      setInfoWindow: () => value => ( InfoWindowobject: value )
    
  ),
  withStateHandlers(
     isOpen: false ,
    
      onToggleOpen: ( isOpen ) => () => (
        isOpen: !isOpen
      )
    
  ),
  withHandlers(
    onMarkerClustererClick: () => markerClusterer => 
      const clickedMarkers = markerClusterer.getMarkers();
    ,
    onMarkerClick: props => markerss => 
      const  setInfoWindow, onToggleOpen  = props;

      axios(
        url: "API",
        method: "POST",

      ).then(res => 

        setInfoWindow(res.data);
        onToggleOpen();
      );
    
  ),
  withScriptjs,
  withGoogleMap
)(props => (
  <GoogleMap
    defaultZoom=5
    defaultCenter= lat: 22.845625996700075, lng: 78.9629 
  >
    <MarkerClusterer
      onClick=props.onMarkerClustererClick
      minimumClusterSize=10
      averageCenter
      styles=[
        
          textColor: "white",
          url: imgmapcluster,
          height: 68,
          lineHeight: 3,
          width: 70
        
      ]
      enableRetinaIcons
      gridSize=60
    >
      props.markers.map((marker, index) => (
        <Marker
          key=index
          icon=user
          onClick=props.onMarkerClick.bind(props, marker)
          position= lat: marker.latitude, lng: marker.longitude 
        />
      ))
      props.isOpen && props.InfoWindowobject !== null && (
        <InfoWindow
          position=
            lat: props.InfoWindowobject.latitude,
            lng: props.InfoWindowobject.longitude
          
          onCloseClick=props.onToggleOpen
        >
          props.InfoWindowobject !== null && (
            <div className="infobox clearfix" style= fontFamily: "Gotham" >
              <div className="header clearfix">
                <h3>
                  props.InfoWindowobject.name," "
                  <small>props.InfoWindowobject.contactNo</small>
                </h3>
              </div>

            </div>
          )
        </InfoWindow>
      )
    </MarkerClusterer>
  </GoogleMap>
));

class DemoApp extends React.PureComponent 
  componentWillMount() 
    this.setState( markers: [], isOpen: false, InfoWindowobject:  );
  

  componentDidMount() 
    axios(
      url: "API",

    ).then(res => 
      this.setState( markers: res.data.data.list );
    );
  

  render() 
    return (
      <MapWithAMarkerClusterer
        markers=this.state.markers
        isOpen=this.state.isOpen
        InfoWindowobject=this.state.InfoWindowobject
      />
    );
  

参考: https://tomchentw.github.io/react-google-maps/#markerclusterer

【问题讨论】:

【参考方案1】:

这是一种预期行为,因为每次状态更改都会重新渲染。 为了防止重新渲染,你可以考虑用 shouldUpdate higher-order component 包裹 MarkerClusterer 组件,让 React 知道组件是否应该受到更改状态的影响,如下所示:

const MyMarkerClusterer = shouldUpdate(checkPropsChange)(props => 
  const onMarkerClick,markers,...clusterProps  = props;
  return (
    <MarkerClusterer 
    ...clusterProps      
    >
      markers.map(marker => (
        <Marker
          key=marker.photo_id
          position= lat: marker.latitude, lng: marker.longitude 
          onClick=onMarkerClick.bind(this, marker)
        />
      ))
    </MarkerClusterer>
  );
);

在哪里

const checkPropsChange = (props, nextProps) => 
  return nextProps.markers.length !== props.markers.length; //re-render only if markers prop changed 
;

Here is a demo

【讨论】:

【参考方案2】:

onMarkerClick 调用 API 和(获取后)两个处理程序:setInfoWindow(),'onToggleOpen`。

两个处理程序都会调用带有状态更改的结果并强制重新呈现嵌入组件 (&lt;GoogleMap/&gt;)。

您应该使用处理程序嵌入&lt;MarkerClusterer/&gt;,并将这个增强的组件作为子组件传递给&lt;GoogleMap/&gt; 组件(或简单地在内部渲染)。

【讨论】:

以上是关于为啥要在标记点击事件上重新渲染地图?的主要内容,如果未能解决你的问题,请参考以下文章

如何在集群中的谷歌地图标记上创建点击事件?

谷歌地图标记事件监听器点击[重复]

我们如何在谷歌地图中添加带有点击事件的多个标记? [复制]

Mapbox GL JS:如果单击标记,则忽略地图单击事件

Angular 9 和谷歌地图标记点击事件无法正常工作

使用角度谷歌地图时如何正确处理标记点击事件?