[Bug]: Invalid prop `sourceID` supplied to `React.Fragment`.
Mapbox Implementation
Mapbox
Mapbox Version
10.19.4
React Native Version
0.78.2
Platform
Android, iOS
@rnmapbox/maps version
10.1.37
Standalone component to reproduce
import React from 'react';
import Mapbox from '@rnmapbox/maps';
function App() {
return (
<Mapbox.MapView style={{flex: 1}}>
<Mapbox.Camera centerCoordinate={[51, 7]} zoomLevel={1} />
<Mapbox.UserLocation showsUserHeadingIndicator={true} />
</Mapbox.MapView>
);
};
export default App;
Observed behavior and steps to reproduce
Move phone to move headingindicator.
Expected behavior
no error
Hi, same here. Any updates?
Same happening here
This is happening when showsUserHeadingIndicator={true} is set to true. This is because in the HeadingIndicator.tsx being wrapped with a fragment and the ShapeSource.tsx component calling cloneReactChildrenWithProps
const HeadingIndicator = ({ heading }: Props) => {
return (
<React.Fragment key="mapboxUserLocationHeadingIndicatorWrapper">
<Images
images={{ userLocationHeading: headingIcon }}
key="mapboxUserLocationHeadingImages"
/>
<SymbolLayer
key="mapboxUserLocationHeadingIndicator"
id="mapboxUserLocationHeadingIndicator"
sourceID="mapboxUserLocation"
belowLayerID="mapboxUserLocationWhiteCircle"
style={{
iconRotate: heading,
...style,
}}
/>
</React.Fragment>
);
};
Simply changing to a View solves the issue
const HeadingIndicator = ({ heading }: Props) => {
return (
<View key="mapboxUserLocationHeadingIndicatorWrapper">
<Images
images={{ userLocationHeading: headingIcon }}
key="mapboxUserLocationHeadingImages"
/>
<SymbolLayer
key="mapboxUserLocationHeadingIndicator"
id="mapboxUserLocationHeadingIndicator"
sourceID="mapboxUserLocation"
belowLayerID="mapboxUserLocationWhiteCircle"
style={{
iconRotate: heading,
...style,
}}
/>
</View>
);
};
If you have a patch file, add this:
diff --git a/node_modules/@rnmapbox/maps/src/components/HeadingIndicator.tsx b/node_modules/@rnmapbox/maps/src/components/HeadingIndicator.tsx
index 03cd306..b5ba9c9 100644
--- a/node_modules/@rnmapbox/maps/src/components/HeadingIndicator.tsx
+++ b/node_modules/@rnmapbox/maps/src/components/HeadingIndicator.tsx
@@ -5,6 +5,7 @@ import { BaseProps } from '../types/BaseProps';
import { SymbolLayer } from './SymbolLayer';
import Images from './Images';
+import { View } from 'react-native';
const style = {
iconImage: 'userLocationHeading',
@@ -19,7 +20,7 @@ type Props = BaseProps & {
const HeadingIndicator = ({ heading }: Props) => {
return (
- <React.Fragment key="mapboxUserLocationHeadingIndicatorWrapper">
+ <View key="mapboxUserLocationHeadingIndicatorWrapper">
<Images
images={{ userLocationHeading: headingIcon }}
key="mapboxUserLocationHeadingImages"
@@ -34,7 +35,7 @@ const HeadingIndicator = ({ heading }: Props) => {
...style,
}}
/>
- </React.Fragment>
+ </View>
);
};
(I appendded it to my current one and I had to have 2 new lines at the end of my file as one of the new lines is part of the diff)
For anyone else coming here by searching for "Invalid prop sourceID supplied to React.Fragment" – I stumbled upon this error by trying to render an empty Fragment as a child, so something like this:
<Mapbox.MapView style={{flex: 1}}>
<Mapbox.Camera centerCoordinate={[51, 7]} zoomLevel={1} />
{ShowPing
? <MapboxGL.CircleLayer
id="location-ping"
style={{ circleRadius: 10 }}
...
/>
: <></> <------ emitting empty fragment
}
</Mapbox.MapView>
A workaround is to use an empty non-Fragment element instead, like <View></View>
For anyone else coming here by searching for "Invalid prop sourceID supplied to React.Fragment" – I stumbled upon this error by trying to render an empty Fragment as a child, so something like this:
<Mapbox.MapView style={{flex: 1}}> <Mapbox.Camera centerCoordinate={[51, 7]} zoomLevel={1} /> {ShowPing ? <MapboxGL.CircleLayer id="location-ping" style={{ circleRadius: 10 }} ... /> : <></> <------ emitting empty fragment } </Mapbox.MapView>A workaround is to use an empty non-Fragment element instead, like
<View></View>
This led me down the right path. I tried using a <View /> here but it does end up throwing a whole different error about it not existing so instead I used null (which will throw a type error) but null should be acceptable in this use case. Casting it to the expected type should avoid the error. Not ideal but it works.
Here is what that looks like in a full example:
import Mapbox from '@rnmapbox/maps';
import type { LineLayerStyleProps } from '@rnmapbox/maps/src/utils/MapboxStyles';
import { useDrawingTools } from '~/lib/hooks/useDrawingTools';
import { useObservationLines } from '~/lib/queries';
import { useStore } from '~/lib/store';
import { PulsingLineLayer } from '../PulsingLineLayer';
export function ObservationLines() {
const { data: observationLinesFeatureCollection } = useObservationLines();
const currentObservationId = useStore((state) => state.currentObservationId);
const isEditing = useDrawingTools((state) => state.isEditing);
if (!observationLinesFeatureCollection) return null;
return (
<Mapbox.ShapeSource
id='observation-lines-shape'
key='observation-lines-shape'
shape={observationLinesFeatureCollection}
>
<Mapbox.LineLayer
id='observation-line-layer'
style={{
lineColor: 'purple',
lineWidth: 10,
lineCap: 'round',
lineJoin: 'round',
} as LineLayerStyleProps}
filter={[
'!=',
['get', '_id'],
currentObservationId,
]}
/>
{/* Overwrite type here. Library expects ReactElement, but null is valid in React. Can't pass in react fragment either otherwise it throws an error. */}
{(!isEditing && currentObservationId) ? <PulsingLineLayer
lineWidth={10}
lineColor='purple'
strokeColor='white'
pulseColor='purple'
sourceID='observation-lines-shape' // prevents it from not showing up due to how the library processes component rendering.
filter={[
'any',
['==', ['get', '_id'], currentObservationId],
['!', !isEditing]
]}
/> : null as unknown as React.ReactElement}
</Mapbox.ShapeSource>
);
}