visgl / react-map-gl

React friendly API wrapper around MapboxGL JS
http://visgl.github.io/react-map-gl/
Other
7.87k stars 1.36k forks source link

question: Considerably lower FPS with react-map-gl compared to mapbox-gl #1151

Closed bkiac closed 2 years ago

bkiac commented 4 years ago

I'm having a considerably lower frame rate with react-map-gl components compared to only using mapbox-gl. In Chrome, sometimes rendering takes twice as much time with react-map-gl. I had better results in Firefox, but it's still slower. Is this expected or am I missing something obvious about how to handle React re-renders more efficiently? Maybe #1000 is related to my problem.

I put together an example and uploaded some results of the Chrome profiler.

Thanks for the help!

Tech Version
react-map-gl 5.2.7
Mapbox GL 1.11.1
React 16.12.0
Firefox 78.0.1
Chrome 83.0.4103.116
OS Fedora 32
bkiac commented 4 years ago

I tested it on more environments, and it seems like there is only a substantial difference in Chrome + Linux for some reason.

nipuna-g commented 4 years ago

I can reproduce this issue with the example attached and on my app. Using CPU throttling(4x) on Chrome makes the difference even more obvious.

The screen capture below is without throttling. pan-zoom-issue

Tech Version
Chrome 81.0.4044.138
OS OSX Catalina(10.15.6)
garretteklof commented 4 years ago

I am too having this issue (and as previously referenced similar to #1000). I will also note that I ran into this issue awhile back (several months) but just scrapped it and went with Leaflet because I did not have time to dig and figured that it was my implementation. However, the native MapboxGL seems to improve things quite a bit (some lag but I'm running it full-screen on a 27" 4K monitor with ~50 tabs open).

Right now, I'm just interested in running this for a side project, but do want to begin moving away from Leaflet/VectorGrid on a much bigger endeavor so I'll be monitoring this.

Can someone speak on the main disadvantages with bootstrapping MapboxGL yourself, as opposed to leveraging this library? I'm not at all trying to discount the library just making sure I understand where the discrepancy could be. This library is really 'just' a wrapper on the initialization and provides convenient hooks into the management of viewport state?

edit: I see that there is a whole suite of components so that's obviously a big advantage

Pessimistress commented 4 years ago

The major difference, and probably where the performance issue originates, is that the camera state of ReactMapGL is managed in React, instead of mapbox-gl. The way mapbox-gl is written is fundamentally incompatible with React, as there are two independent rendering cycles: React's rendering logic, and Mapbox's own animation loop. When you update component props/states, react-map-gl has to synchronize the rendering of React components and the map itself. We have two options:

We currently use the first approach. This means that redraws happen at React's discretion. React may decide to render more than necessary than Mapbox would on its own, failing to account for how expensive the draw call is.

If you are using mapbox as nothing but a map display, generally speaking you do not need this library. If you are trying to match the map with any other React component, you will eventually run into the same issue.

dyakovlev commented 3 years ago

We're running into this issue as well, using Mapbox GL and ReactMapGL in an interactive application. It seems to have gotten worse in the last few months.

I had some success in throttling viewport updates, as it seemed that the sheer quantity emitted when panning a map was flooding the InteractiveMap component to the point of it no longer rendering at all.

Some basic profiling points to a lot more of setState in InteractiveMap than anything else, but I haven't absorbed it in depth.

Would it be viable to emit viewport state updates in reaction to motion, but to allow the GL instance to pan itself instead of being controlled by props?

Pessimistress commented 3 years ago

You can set asyncRender={true} on the map component. This will cause the React Markers & Popups to go out of sync during viewport updates, but have been reported to improve the render performance.

spiffistan commented 3 years ago

Running into this issue as well. Zooming and panning is super slow, especially with trackpads, and transitionDuration does nothing to ameliorate the problem. It seems to be the setState for viewport updates causing the problem.

dyakovlev commented 3 years ago

^^ yes, we've had to throttle viewport updates for scrolling and panning events to once per 30ms, as unfortunately we have on-screen elements that go out of sync with asyncRender. (performance did get a lot better, but the state tearing was visually unacceptable)

It's consistently choppy, but feels better than being inconsistently choppy.

justindchan commented 3 years ago

IF one uses the original mapbox api and not the react library is this problem alleviated?

Pessimistress commented 2 years ago

This is being addressed in v7.0. Please follow #1646

JessicaBunyan commented 2 years ago

Just as info for any future searchers, we switched to mapbox v7 and used the uncontrolled map component, as well as using geoJSON to show markers with a datalayer (with step expressions to show different markers if needed)

With these changes we went from struggling at 200 markers (unusable at 300) to showing 1400 and is smoother than ever

Our challenges with this were:

  1. Accessibility / tab navigation - this is lost when using geojson rather than react elements
  2. Programmatic pan/zoom - This is lost when using uncontrolled map component. We circumvented this by unloading/reloading the map when we need to do this, by re-setting its key prop. Its not ideal but it does the job after a fashion This can be handled with a ref on the map and map.easeTo or map.jumpTo
Pessimistress commented 2 years ago

Programmatic pan/zoom

You can call map.easeTo and map.jumpTo using a ref.

JessicaBunyan commented 2 years ago

That's great, thanks for the info @Pessimistress !