[Bug]: multiple async URI in <images> do not render on android
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 2.9k
- Forks
- 947
- Avg merge
- 6d 37m
- Merged PRs (30d)
- 1
Description
Mapbox Implementation
Mapbox
Mapbox Version
11.15.3
React Native Version
0.81.4
React Native Architecture
New Architecture (Fabric/TurboModules)
Platform
Android
@rnmapbox/maps version
10.2.5
Standalone component to reproduce
// BugReportExampleSymbols.js (pure JS)
import React, {useCallback, useMemo, useState} from 'react';
import {
MapView,
ShapeSource,
SymbolLayer,
Camera,
Images,
} from '@rnmapbox/maps';
import {View, Button, StyleSheet} from 'react-native';
// If needed in your app entry, remember to set your token:
// import Mapbox from '@rnmapbox/maps';
// Mapbox.setAccessToken('YOUR_TOKEN');
const CENTER = [-74.00597, 40.71427];
const PIN_URL =
'https://raw.githubusercontent.com/rnmapbox/maps/refs/heads/main/example/src/assets/pin.png';
const EMPTY_FC = {
type: 'FeatureCollection',
features: [],
};
const layerStyle = {
iconImage: ['get', 'icon'], // read image id from feature properties.icon
iconAllowOverlap: true,
iconIgnorePlacement: true,
iconSize: 0.7,
};
function makeRandomPoints(count, around) {
const [lng, lat] = around;
const features = [];
for (let i = 0; i < count; i++) {
// small jitter around center
const dx = (Math.random() - 0.5) * 0.01;
const dy = (Math.random() - 0.5) * 0.01;
features.push({
type: 'Feature',
id: `pt-${i}`,
properties: {
icon: `pin-${i}`, // unique image id per point
},
geometry: {
type: 'Point',
coordinates: [lng + dx, lat + dy],
},
});
}
return {type: 'FeatureCollection', features};
}
export default function BugReportExampleSymbols() {
const [fc, setFc] = useState(EMPTY_FC);
const [imgs, setImgs] = useState({});
const loadPointsAndImages = useCallback(() => {
// 1) Prepare 10 unique image IDs (all backed by the SAME URL)
const nextImgs = {};
for (let i = 0; i < 10; i++) {
// cache-bust query so RN treats them as distinct if needed
nextImgs[`pin-${i}`] = {uri: `${PIN_URL}?v=${i}`};
}
setImgs(nextImgs);
// 2) Create 10 point features that reference the above image ids
setFc(makeRandomPoints(10, CENTER));
}, []);
const clearAll = useCallback(() => {
setImgs({});
setFc(EMPTY_FC);
}, []);
const camera = useMemo(
() => <Camera centerCoordinate={CENTER} zoomLevel={14} />,
[],
);
return (
<View style={styles.container}>
<View style={styles.row}>
<Button title="Load 10 points + images" onPress={loadPointsAndImages} />
<View style={styles.spacer} />
<Button title="Clear" onPress={clearAll} />
</View>
<MapView style={styles.map}>
{camera}
{/* Provide images so SymbolLayer can resolve icon ids */}
<Images images={imgs} />
<ShapeSource id="bug-symbol-source" shape={fc}>
<SymbolLayer id="bug-symbol-layer" style={layerStyle} />
</ShapeSource>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: {flex: 1},
row: {
flexDirection: 'row',
padding: 8,
gap: 8,
backgroundColor: '#ffffff',
zIndex: 1,
},
spacer: {width: 8},
map: {flex: 1},
});
Observed behavior and steps to reproduce
The images are resolved to a URI and set on the <images> component. But the images are never rendered to the screen or if they are only 1 or two is.
To reproduce, just run the code and then click the button to load the pins.
Expected behavior
It should render the pins on the map.
Notes / preliminary analysis
It appears to be a race condition of some sort because if i pause the code after react starts processing the set images it will render them all.
Additional links and references
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the reproduction in BugReportExampleSymbols.js on Android and pressing “Load 10 points + images.” Read the @rnmapbox/maps Images component and the SymbolLayer usage shown in the example. Done means all 10 pins render reliably rather than only one or two.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, javascript, react-native
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100