Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unmounting Markers performance #210

Closed
dwickstrom opened this issue Feb 16, 2016 · 17 comments
Closed

Unmounting Markers performance #210

dwickstrom opened this issue Feb 16, 2016 · 17 comments

Comments

@dwickstrom
Copy link

Hello people,

I might have ran into some kind of limiting factor regarding this library in connection with rendering, or rather the un-rendering a larger amount of markers.

The problem is that it takes a very long tim (about 10 seconds) for React to re-render when transitioning between state 1 to 2.

State #1
~1000 pretty simple and straight forward javascript objects are held in a state key in my React component. Each of them are also rendered into the DOM by React like so:

const infoWindow = (this.props.infoWindows.includes(marker.id)) ? this.renderInfoWindow(ref, marker, i) : null;
return (
  <Marker
    {...marker}
    position={marker.position}
    icon={buildIconObject(marker.type, marker.state)}
    key={i}
    ref={ref}
    onClick={this.props.handleMarkerClick.bind(marker, marker.id)}
    infoWindow={infoWindow}>
  </Marker>
)

State #2

About 20 javascript objects rendered in the same way as the above.

For some reason it takes forever (about 10 seconds) to set the new state object:

this.setState({
  markers: newMarkers, // replacing the array of ~1000 markers with ~20
})

I have tried to remove everything except the position key from the marker component to se if there was some kind of problem, but it didn't help at all. I have also tried dropping the <Marker /> altogether and instead plot the markers with Google's components directly and then use marker.setMap(this._googleMapComponent.props.map) to render it into the DOM. This solved the problem, I think, since the delay was gone. However, that might be because I didn't remove them from the DOM when the React state was changed. That might be clue as to what's going on.

In essence, my question is, why does the removing all these markers seem to take such a long time?

Does this sound familiar or spark any ideas?

@dwickstrom
Copy link
Author

Update: I forgot to mention that I also used the <MarkerClusterer /> component like so:

 return (
      <MarkerClusterer
        averageCenter={ true }
        enableRetinaIcons={ false }
        styles={mcOptions}
        gridSize={20}>
        {markers}
      </MarkerClusterer>
    )

Turning that off, was the whole difference actually, so now I have to figure out why this is such a performance hog in my case.

@joelwurtz
Copy link

We also faced this problem,

In fact the latency comes from how the marker is added to the cluster, when the marker is added or removed, it uses the addMarker / removeMarker from the library which will do a repaint.

So in fact removing 800 markers, i.e, will call 800 times the repaint method of the marker clusterer (and same when adding 800 markers)

Our workaround for the moment was to rewrite the MarkerClusterer and when a marker is removed or added we save it to an array. Then on the componentDidUpdate of the MarkerClusterer we use the removeMarkers / addMarkers batch methods which are designed to remove / add markers in mass.

Also another optimisation was to remove the repaint method after each update of the component as it's already well handled by the underlying library.

@amangeot
Copy link
Contributor

amangeot commented Apr 18, 2016

Hi @joelwurtz , i'm facing the same problem. I have about 10k markers placed in MarkerClusterer which takes some time when mounting the map for the first time.

Is there any chance you could share the improvement you made on MarkerClusterer ? Or a link that shows the performance you obtained ?

I also have a question if you don't mind: is it reasonable to use the idle map event to only display markers/clusters in that are visible in current map bounds ? with your optimisation ?

Thank you, and thanks for all the work that was put in this library !

@tomchentw
Copy link
Owner

We're going to look into this shortly.

We're also looking for maintainers. Involve in #266 to help strengthen our community!

tomchentw pushed a commit that referenced this issue May 30, 2016
* Improved performance of rendering many markers/components on the map
* Closes #135
* Closes #210
* Closes #216

BREAKING CHANGE: If you're just using the library and didn't make custom components before, feel free to ignore this implementation changes.

Now, mapHolderRef for each component are now passed in via context. This doesn't affect all components interface in general. But if you do custom components before and relies on the implementation of react-google-maps, you should be aware of this and make some changes.
@amangeot
Copy link
Contributor

Hello,
@tomchentw, could you confirm that the "repainting issue" is still fixed in v6?

I have map with a lot of clustered markers (about 8k). I add them all on the map without any filtering trick, it works wonderfully but it takes time to mount when first loading the page. I guess this is normal, but it takes time to unmount when going from '/map' to let's say '/dashboard'.

Thank you,

@cezarneaga
Copy link

@joelwurtz could you please share your solution. the re-rendering doesnt work for me still

@amangeot
Copy link
Contributor

Not sure if if it will work for you but you could check this issue:
#395

That I tried to solve this way: #397

@tomchentw
Copy link
Owner

Please refer to Getting Help section in the README (or #469).

@frosato-dev
Copy link

I'm using version "9.4.5" and I'm still facing this performance issue.
I got a MarkerCluster with ~1000 Markers inside.
When updating the number of Markers from ~1000 to x (after a filter action on my locations) the repaint takes ages and even leads to my browser window to crash.
I know the issue is old and closed but am I missing something?
Moreover, I would like to use Marker and MarkerCluser custom icons but it also seems to have a strong impact on performance. Do you have any recommendation to make all this work?

@mschipperheyn
Copy link

I'm facing the same problem. There is a NoRedraw boolean option the Marker tag, I find that it insufficiently resolves the issue. Possible solution directions:

  • fork this component and use React.Fragment instead of div to render the marker. I have a hunch that that might help
  • fork this component and use the react-marker-clusterer api to create your cluster
  • Make your database smarter so you can select only a minimum amount of markers per cluster

@tab
Copy link

tab commented Aug 6, 2018

Update to latest package (9.4.5) version and use option noRedraw={true} solved all problems

@dexterns88
Copy link

noRedraw={true} not helping in my case where I have over 1k markers.

@stenrdj
Copy link

stenrdj commented Oct 2, 2018

Hey guys , I still have the same issue , i updated to 9.4.5 latest as mentioned above , also added noRedraw attribute to Marker and i couldn't see any improvements on markers hover :/ .
@tab please how did you make it ? did you got out Marker component from render method ? thanks

@tab
Copy link

tab commented Oct 2, 2018

@stenrdj

I have problems with performance. I have about 3000 markers on the map and markers joins in clusters.
Each marker have categories. Process of redrawing markers when choosing one category took 1-2 minutes.
With noRedraw={true} it takes 1-2 seconds.

container-component with map HomeMap.jsx:

import React, { Component } from 'react'
import { withScriptjs, withGoogleMap, GoogleMap } from "react-google-maps"
import { MarkerClusterer } from "react-google-maps/lib/components/addons/MarkerClusterer"
...
import HomeMapMarker from './HomeMapMarker'

const clusterGridSize = 120;
const clusterMaxZoom = 18;

class HomeMap extends Component {

  constructor(props) {
    super(props);
  }

...

  renderMarkers() {
    const { ideas } = this.props;
    return ideas.filter((idea) => idea.coordinates_present).map(function(idea) {
      return (
          <HomeMapMarker key={idea.id}
                         idea={idea}
                         previewVisible={idea.id === this.state.ideaPreviewId}
                         onClick={this.handleMarkerClick}
                         onClosePreview={this.handlePreviewClose} />
      )
    }, this)
  }

  render() {
    const { defaultZoom, defaultCenter, onMapMount } = this.props;
    const options = {
      disableDefaultUI: true,
      zoomControl: true,
      scrollwheel: false,
      clickableIcons: false,
      fullscreenControl: true
    };

    return (
        <GoogleMap defaultZoom={defaultZoom}
                   defaultCenter={defaultCenter}
                   defaultOptions={options}
                   center={defaultCenter}
                   ref={onMapMount}
                   onClick={this.handleClick}>
          <MarkerClusterer
              averageCenter
              enableRetinaIcons
              gridSize={clusterGridSize}
              styles={clusterStyles()}
              maxZoom={clusterMaxZoom}>
            { this.renderMarkers() }
          </MarkerClusterer>
        </GoogleMap>
    )
  }
}

...

and HomeMapMarker.jsx:

import React, { Component } from 'react'
import { Marker } from "react-google-maps"
import { InfoBox } from "react-google-maps/lib/components/addons/InfoBox"
...

class HomeMapMarker extends Component {

  constructor(props) {
    super(props);
  }
...

  render() {
    const { idea, onClick } = this.props;
    return (
        <Marker noRedraw={true}
                position={this.markerPosition()}
                icon={markerIcon()}
                onClick={() => onClick(idea)}>
          {this.renderPopup()}
        </Marker>
    )
  }
}

export default HomeMapMarker

@stenrdj
Copy link

stenrdj commented Oct 2, 2018

Thanks @tab , absolutely i have the same issue , about 2400 marker , hover (change icon to active one) takes about 2~3s and thats relatively a lot of user . i want just to make sure if the method used in code above you just shared is gonna save my life .

@OrenSchwartz
Copy link

Hello, is this solved in any way ? I'm experiencing this sluggish behaviour for 400 markers.

@JustFly1984
Copy link

@OrenSchwartz this library is not maintained about a year, please consider switching to it's successor rewritten with Typescript - @react-google-maps/api

https://www.npmjs.com/package/@react-google-maps/api

We have active community on spectrum, working examples and docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests