feat(mapbox): Replace shadow transform with proxied approach #2514
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is a pretty big change to how we handle controlled Mapbox instance.
Background
The basis of our approach is that we keep two Transform instances: one that Map can mutate freely, and one that is controlled by React props.
In 7.x and 8.0, we created a
renderTransform
as the controlled instance. The mutable instance is the permanent source of truth of the map state. Its changes are merged with React props and synchronized back torenderTransform
. During 1. render, 2. query and 3. event callbacks,renderTransform
is swapped in so the map reads the controlled matrices.We have made a lot of hacks and patches around this approach, and there still are a handful of long-standing issues, mostly around terrain and non-mercator projection. The source of the grievance is that
map.transform
on various lifecycle stages and some of them do not trigger an event.map.flyTo
centers on the incorrect spot when terrain is enabled. #2194, [Bug] When 3D Terrain is enabled, updating state in React causes Markers to render in their original locations, instead of on top of the terrain. #2088, Pointer event lat lng position doesn't factor in terrain #2248). New features can also fail to be synchronized ([Bug] v8.x does not display Mapbox road labels when using Standard Styles #2506).Changes
This PR proposes a (hopefully) cleaner approach. We replace
map.transform
with aProxyTransform
, which uses Proxy to trap get and set operations. Under the hood, it manages the two Transform instances (freely mutableproposedTransform
and React-controlledcontrolledTransform
). Of the two,controlledTransform
is the permanent source of truth, andproposedTransform
is only temporarily populated IF the map is controlled AND during a move session. This results in much better consistency in map behavior:initialViewState
) there is only one transform instance, which should minimize the perf/bugs impact from our wrapperI am also trying to document inline extensively to improve code readability.
Release plan
Targeting a v8.1 release.
I am leaning towards NOT back porting this to
mapbox-legacy
, which is mainly used for mapbox-gl@1 and will be eventually deprecated. The old approach works fairly well for the basic (no terrain or alt projection) use case. The new approach relies heavily on the internals of theTransform
class and the official types. I did a quick audit and most of the private methods have existed since v2.0. However we do not test with non-latest mapbox versions and it could become a maintenance hazard.