It's a bit random but happens a lot, I'd say at least ~50% of the times when you reload CMD+R on iOS simulator and also on a real iOS device.
An example of code:
import React, { Component } from 'react';
import MapboxGL from '@mapbox/react-native-mapbox-gl';
const markerPremium = require('../../images/pin_premium.png');
const markerPremiumSelected = require('../../images/pin_premium_selected.png');
const layerStyles = MapboxGL.StyleSheet.create({
icon: {
iconAllowOverlap: true,
iconIgnorePlacement: true,
iconSize: Platform.OS === 'android' ? 1 : 0.5,
iconOffset: [0, 5],
textField: '{discountPercentage}%',
textSize: 14,
},
iconPremium: {
iconImage: markerPremium,
textColor: '#fff',
textHaloColor: '#fff',
textHaloWidth: 0.3,
},
iconPremiumSelected: {
iconImage: markerPremiumSelected,
textColor: '#D7B218',
textHaloColor: '#D7B218',
textHaloWidth: 0.1,
},
});
class MapPremium extends Component {
state = {
markers: [],
};
componentDidMount() {
this.generateMarkers();
}
componentWillReceiveProps(newProps) {
this.generateMarkers(newProps);
}
generateMarkers = (props = this.props) => {
const { listRestaurants, listPremium } = props;
const markers = listPremium.map((premiumOffer) => {
const restaurant = listRestaurants[premiumOffer.restaurantId];
return {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [restaurant.lng, restaurant.lat],
},
id: premiumOffer.id,
properties: {
offerId: premiumOffer.id,
markerOffer: true,
restaurantId: restaurant.id,
discountPercentage: premiumOffer.discountPercentage,
isSelected: premiumOffer.id === props.selectedOfferId,
},
};
});
this.setState({ markers });
};
render() {
return (
<MapboxGL.MapView
style={{ flex: 1, backgroundColor: '#232224' }}
centerCoordinate={[8.5333396, 47.388]}
zoomLevel={12}
styleURL="mapbox://styles/mealseaty/cj8j606p93rmj2rojy4in2h9r"
onPress={() => this.props.clearMarker()}
>
<MapboxGL.ShapeSource
id="premiumOffers"
shape={{
type: 'FeatureCollection',
features: this.state.markers,
}}
cluster
clusterMaxZoomLevel={14}
clusterRadius={50}
onPress={(e) => {
const { offerId, restaurantId } = e.nativeEvent.payload.properties;
if (offerId) this.props.selectMarker(offerId, restaurantId);
}}
>
<MapboxGL.SymbolLayer id="pointCount" style={layerStyles.clusterCount} />
<MapboxGL.CircleLayer
id="clusteredPoints"
belowLayerID="pointCount"
filter={['has', 'point_count']}
style={layerStyles.clusteredPoints}
/>
<MapboxGL.SymbolLayer
id="singlePoint"
filter={['all', ['!has', 'point_count'], ['==', 'isSelected', false]]}
style={[layerStyles.icon, layerStyles.iconPremium]}
/>
<MapboxGL.SymbolLayer
id="singlePointSelected"
filter={['all', ['!has', 'point_count'], ['==', 'isSelected', true]]}
style={[layerStyles.icon, layerStyles.iconPremiumSelected]}
/>
</MapboxGL.ShapeSource>
</MapboxGL.MapView>
);
}
}
Not loaded correctly:
Loaded correctly:

@mtt87 @jsaguiar are you guys running into this on Android as well? I'll start digging into this today
Haven't tested yet on Android but I can do a quick test tonight and let you know!
Do you think using the assets in Xcode could make this easier?
In that case how would you reference them in the code?
Thank you 馃槃
I am running only in iOS for now. I am also using ShapeSource and I have the same problem
I believe this issue https://github.com/mapbox/react-native-mapbox-gl/issues/920 is also related to the same problem as this.
What I've discovered so far is when we fetch the image to be put onto the map style there is no guarantee that our callback block will be executed on the main thread, and my code is under the assumption that we are on the main thread.
Once I updated the code to do this
[RCTMGLUtils fetchImage:_bridge url:styleValue.payload[@"value"] callback:^(NSError *error, UIImage *image) {
if (image != nil) {
dispatch_async(dispatch_get_main_queue(), ^{
[_style setImage:image forName:styleValue.payload[@"value"]];
[self setIconImage:layer withReactStyleValue:styleValue];
});
}
}];
I stopped seeing the crash and random markers not appearing, on the example that I am testing with. This could explain why this has been so random, because sometimes the code would have been called on the main thread instead of a background thread
Awesome @nitaliano , 馃 it might be that!
Also 2 birds with 1 stone 馃槃
I wish I could help more but unfortunately my reign is JS and I'm not good with swift/obj-c 馃槩
Gonna test soon with Android, if that doesn't happen then we might be quite sure it's related to this.
PS: where did you update that code? @nitaliano
I updated it here
Can I try the latest version on master and play around with it to check if everything is okay?
yea, you can update the code manually on the latest master if you want to mess around with it. I'm also going to keep playing around with it to see if it really did fix this problem, and PR it later today
Testing with Android (both simulator and real device) there are no crashes at all but again sometimes the custom png markers are not loaded correctly or something strange happens, the first load is correct then they become black.
First load correct

Tap something they become black

This is instead what happened on a real device (no markers at all loaded):
Also @nitaliano I just added your code for iOS and I get this warning on Xcode

There are a few places where we use that code make sure you are in method
- (void)symbolLayer:(MGLSymbolStyleLayer *)layer withReactStyle:(NSDictionary *)reactStyle
the warning above is saying you're in
- (void)fillLayer:(MGLFillStyleLayer *)layer withReactStyle:(NSDictionary *)reactStyle
I was following your link in the original post was on line 60 馃槃 I saw your edit now 馃槃
That said it seems to be working fine on the simulator, no crashes at all.
Still on the real device the markers are not loaded correctly.
I'll try to resave those png to check if it's not something wrong with it.
I just did a test and if I load the custom marker with Images.xcassets they work correctly in both the simulator and the real device
Using this code:
const layerStyles = MapboxGL.StyleSheet.create({
iconPremium: {
iconImage: 'pin_premium',
...
},
<MapboxGL.ShapeSource
images={{ assets: ['pin_premium'] }}
...
>
I just figured out what's going on the JS is sending an invalid uri down to the native code, when the application is put into release mode.
The above approach works, because we're just pulling them out of their native directories when we want to set the image on the map style. This is also my preferred way of doing it because it also handles different dpis correctly
I moved all my pinpoint assets to Images.xcassets I don't mind leaving them there to be honest, looks like also they load faster or maybe it's just an impression.
@mtt87 it's definitely going to be faster(probably not by much) pulling the images out of Images.xcassets as we are removing all bridge passes for getting the image
@mtt87 For me in iOS seams to be working with images loaded from RN! But that behaviour was really rare! If it happens again I will let you know!
PR is out that fixes icons not appearing in release mode https://github.com/mapbox/react-native-mapbox-gl/pull/922
@mtt87 fix has been merged into master going to close this out will be published in 6.0.3
@mtt87 Hi, I am new to react and maps in general. I am wondering how do you get that 'point_count' property? I have a ShapeSource with clustering active and I would like to get somehow the number of elements that are clustered for that point, if any at all.
Thanks
@ciulhycutza I'm not sure if there is a way to get it as a callback or prop.
The way it works is hidden to the user, you just render stuff based on the fact that point_count is automatically calculated by the MapView and you can use filters to hide/show stuff based on that value.
If you wanna print the value you can have something like this
const layerStyles = MapboxGL.StyleSheet.create({
clusteredPoints: {
circleColor: MapboxGL.StyleSheet.source(
[[2, '#0ca843']],
'point_count',
MapboxGL.InterpolationMode.Exponential,
),
circleRadius: MapboxGL.StyleSheet.source(
[[2, 21]],
'point_count',
MapboxGL.InterpolationMode.Exponential,
),
circleStrokeWidth: 2,
circleStrokeColor: 'white',
},
clusterCount: {
textField: '{point_count}',
textSize: 18,
textHaloColor: '#fff',
textHaloWidth: 0.3,
textColor: '#fff',
},
});
...
<MapboxGL.SymbolLayer id="pointCount" style={layerStyles.clusterCount} />
<MapboxGL.CircleLayer
id="clusteredPoints"
belowLayerID="pointCount"
filter={['has', 'point_count']}
style={layerStyles.clusteredPoints}
/>
Done. Thanks.
Testing with Android (both simulator and real device) there are no crashes at all but again sometimes the custom png markers are not loaded correctly or something strange happens, the first load is correct then they become black.
First load correct
Tap something they become black
This is instead what happened on a real device (no markers at all loaded):
What is status of this? I have this problem on Android with 6.1.3.
Is using native assets solution? If it is, it might still be worth fixing.
@mtt87 can you give me source code for refer. I can't find any document for selected marker on mapbox. pls and many thanks!
@uyit14 You can do something like this, I copy&pasted from my app removing stuff that was not related cause I don't have a lot of time right now but you should understand how it works
const layerStyles = MapboxGL.StyleSheet.create({
icon: {
iconAllowOverlap: true,
iconIgnorePlacement: true,
iconSize: 0.8,
iconImage: 'iconAsset',
},
iconSelected: {
iconImage: 'iconSelectedAsset',
iconSize: 1,
},
});
class MapWithMarker extends Component {
constructor() {
super();
this.state = {
selectedMarkerId: null
}
}
render() {
const marker1 = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [45.001, 8],
},
id: '1',
properties: {
isSelected: this.state.isSelected === '1',
},
};
const marker2 = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [45.002, 8],
},
id: '2',
properties: {
isSelected: this.state.isSelected === '2',
},
};
const markers = [marker1, marker2];
return (
<MapboxGL.MapView>
<MapboxGL.ShapeSource
id="my_markers"
shape={{
type: 'FeatureCollection',
features: markers,
}}
onPress={(e) => {
const payload = { ...e.nativeEvent.payload };
const { id } = payload;
if (id) {
this.setState({ selectedMarkerId: id });
}
return null;
}}
images={{ assets: ['iconAsset', 'iconSelectedAsset'] }}
>
<MapboxGL.SymbolLayer
id="singlePoint"
filter={['==', 'isSelected', false]}
style={layerStyles.icon}
/>
<MapboxGL.SymbolLayer
id="singlePointSelected"
filter={['==', 'isSelected', true]}
style={[layerStyles.icon, layerStyles.iconSelected]}
/>
</MapboxGL.ShapeSource>
</MapboxGL.MapView>
);
}
}
I am still having this issue in 7.0.2. Around 50% of the time, no custom png icons are displayed. This applies to all icons on the map. This is a simple example of one of the components:
import React from "react";
import MapboxGL, { SymbolLayerStyle } from "@react-native-mapbox-gl/maps";
interface Props {
coordinates: [number, number];
bearing?: number;
}
const style: SymbolLayerStyle = {
iconImage: require("../../Images/Icons/map/position-dot.png"),
iconSize: 0.5,
};
const directionStyle: SymbolLayerStyle = {
iconImage: require("../../Images/Icons/map/position-dot-direction.png"),
iconSize: 0.5,
};
export const BlueDot: React.FC<Props> = ({ coordinates, bearing }) => {
return (
<MapboxGL.ShapeSource
id="mapboxUserLocation"
shape={{ type: "Point", coordinates }}
>
{bearing !== undefined && (
<MapboxGL.SymbolLayer
id={`bluedot-direction`}
style={{ ...directionStyle, iconRotate: bearing }}
/>
)}
<MapboxGL.SymbolLayer id={`bluedot-symbol`} style={style} />
</MapboxGL.ShapeSource>
);
};
export default BlueDot;
Most helpful comment
@mtt87 fix has been merged into master going to close this out will be published in
6.0.3