-
Notifications
You must be signed in to change notification settings - Fork 13
fix: stop mapbox pins from flickering #628
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -155,6 +155,7 @@ export function MapboxMap<T>({ | |||||||||
| markerOptionsOverride, | ||||||||||
| }: MapboxMapProps<T>): React.JSX.Element { | ||||||||||
| const mapboxInstance = (iframeWindow as Window & { mapboxgl?: typeof mapboxgl })?.mapboxgl ?? mapboxgl; | ||||||||||
| // keep the mapbox access token in sync with prop changes. | ||||||||||
| useEffect(() => { | ||||||||||
| mapboxInstance.accessToken = mapboxAccessToken; | ||||||||||
| }, [mapboxAccessToken, mapboxInstance]); | ||||||||||
|
|
@@ -175,6 +176,7 @@ export function MapboxMap<T>({ | |||||||||
| setSelectedResult(prev => prev === result ? undefined : result); | ||||||||||
| }, []); | ||||||||||
|
|
||||||||||
| // notify consumers when the selected pin changes. | ||||||||||
| useEffect(() => { | ||||||||||
| onPinClick?.(selectedResult); | ||||||||||
| }, [onPinClick, selectedResult]); | ||||||||||
|
|
@@ -192,6 +194,8 @@ export function MapboxMap<T>({ | |||||||||
| if (supportsCreateRoot) { | ||||||||||
| const root = markerRoots.current.get(element); | ||||||||||
| if (root) { | ||||||||||
| // unmount must be called after the current render finishes, so schedule it for the next | ||||||||||
| // microtask | ||||||||||
| scheduleRootUnmount(root); | ||||||||||
| markerRoots.current.delete(element); | ||||||||||
| } | ||||||||||
|
|
@@ -215,12 +219,74 @@ export function MapboxMap<T>({ | |||||||||
| } | ||||||||||
| }, []); | ||||||||||
|
|
||||||||||
| // builds and attaches a single marker to the mapbox map | ||||||||||
| const createMarker = useCallback(( | ||||||||||
| mapbox: mapboxgl.Map, | ||||||||||
| result: Result<T>, | ||||||||||
| index: number, | ||||||||||
| selected: boolean | ||||||||||
| ) => { | ||||||||||
| const markerLocation = getCoordinate(result); | ||||||||||
| if (!markerLocation) { | ||||||||||
| return null; | ||||||||||
| } | ||||||||||
| const { latitude, longitude } = markerLocation; | ||||||||||
| if (!Number.isFinite(latitude) || !Number.isFinite(longitude)) { | ||||||||||
| return null; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const el = document.createElement('div'); | ||||||||||
| let markerOptions: mapboxgl.MarkerOptions = {}; | ||||||||||
| if (PinComponent) { | ||||||||||
| if (renderPin) { | ||||||||||
| console.warn( | ||||||||||
| 'Found both PinComponent and renderPin props. Using PinComponent.' | ||||||||||
| ); | ||||||||||
| } | ||||||||||
| attachPinComponent(el, ( | ||||||||||
| <PinComponent | ||||||||||
| index={index} | ||||||||||
| mapbox={mapbox} | ||||||||||
| result={result} | ||||||||||
| selected={selected} | ||||||||||
| /> | ||||||||||
| )); | ||||||||||
| markerOptions.element = el; | ||||||||||
| } else if (renderPin) { | ||||||||||
| renderPin({ index, mapbox, result, container: el }); | ||||||||||
| markerOptions.element = el; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (markerOptionsOverride) { | ||||||||||
| markerOptions = { | ||||||||||
| ...markerOptions, | ||||||||||
| ...markerOptionsOverride(selected) | ||||||||||
| }; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| const marker = new mapboxInstance.Marker(markerOptions) | ||||||||||
| .setLngLat({ lat: latitude, lng: longitude }) | ||||||||||
| .addTo(mapbox); | ||||||||||
|
|
||||||||||
| marker?.getElement().addEventListener('click', () => handlePinClick(result)); | ||||||||||
|
||||||||||
| marker?.getElement().addEventListener('click', () => handlePinClick(result)); | |
| marker.getElement()?.addEventListener('click', () => handlePinClick(result)); |
Copilot
AI
Feb 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When locationResults changes, the selectedResult effects (lines 506-547 and 549-569) may run with stale markerData.current before the new markers are created. Consider resetting previousSelectedResult.current to undefined in the locationResults effect cleanup function, or at the start of the locationResults effect, to prevent attempting to update markers that no longer exist.
| useEffect(() => { | |
| useEffect(() => { | |
| // Reset previousSelectedResult to avoid referencing markers that have been removed. | |
| previousSelectedResult.current = undefined; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,6 +108,7 @@ export function LocationsPage() { | |
| <MapboxMap | ||
| mapboxAccessToken={process.env.REACT_APP_MAPBOX_API_KEY || 'REPLACE_KEY'} | ||
| mapboxOptions={mapboxOptions} | ||
| // markerOptionsOverride={markerOptionsOverride} | ||
|
||
| PinComponent={MapPin} | ||
| onDrag={onDrag} | ||
| /> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The renderPin function call is missing the
selectedparameter. According to the PinComponentProps type definition (line 38), the selected property should be passed to renderPin. This should be:renderPin({ index, mapbox, result, selected, container: el })