maps icon indicating copy to clipboard operation
maps copied to clipboard

[Bug]: Invalid prop `sourceID` supplied to `React.Fragment`.

Open cixio opened this issue 8 months ago • 4 comments

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

cixio avatar Apr 04 '25 22:04 cixio

Hi, same here. Any updates?

AleeeKoi avatar May 22 '25 16:05 AleeeKoi

Same happening here

soldiweb avatar May 22 '25 16:05 soldiweb

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)

RussMax783 avatar May 28 '25 23:05 RussMax783

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>

skiqh avatar Jun 17 '25 15:06 skiqh

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>
  );
}

Streudal avatar Jun 18 '25 19:06 Streudal