maps icon indicating copy to clipboard operation
maps copied to clipboard

PointAnnotation in wrong position when added to MapView after MapView's first render

Open bwiitttyyyyy opened this issue 2 years ago • 4 comments

Describe the bug
On iOS (everything works as intended on Android), when a PointAnnotation is added as a child of a MapView, without prompting a re-mount of the MapView, the PointAnnotation is displayed in the top left corner of the device and not at the coordinate specified in the PointAnnotation's props. This sequence of events is occurring in the following use case: app opens, begins loading content, map renders, content loads, PointAnnotations are created based on loaded content.

The PointAnnotations are not first direct children of the MapView. There is a child of the MapView which itself has children which are PointAnnotations.

We are rendering CircleLayers based on a Source along side the PointAnnotations. We do not want the Map to re-mount (along with its CircleLayer) as the PointAnnotations are added/deleted/changed often, and it would be inefficient to re-mount the map each time.

To Reproduce Though in our working code the Map's lifecycle is managed by the lifecycle methods, the same effect can be created using the below code and Metro. If you run the below code on a device, leaving the 6th entry of the 'coordinates' array commented, then uncomment the 6th line, and write the file (triggering a reload from Metro) the MapView will not re-mount, but the components will re-render. The PointAnnotation created from the 6th entry will display in the top left corner of the screen.

Example:

import React from 'react'
import { View } from 'react-native'
import {
  MapView,
  ShapeSource,
  LineLayer,
  PointAnnotation,
  Camera,
} from '@rnmapbox/maps'

class App extends React.Component {
  render () {
    const coordinates = [
      [ Math.random() * 360 - 180, Math.random() * 180 - 90 ],
      [ Math.random() * 360 - 180, Math.random() * 180 - 90 ],
      [ Math.random() * 360 - 180, Math.random() * 180 - 90 ],
      [ Math.random() * 360 - 180, Math.random() * 180 - 90 ],
      [ Math.random() * 360 - 180, Math.random() * 180 - 90 ]
      //[ Math.random() * 360 - 180, Math.random() * 180 - 90 ]
    ]

    return (
      <MapView>
        <ChildA />
        <ChildB
          annotations={coordinates}
        />
      </MapView>
    )
  }
}

class ChildB extends React.Component {
 render () {
   const { annotations } = this.props
  return (
    <View>
      {annotations.map((annotation) => (
        <PointAnnotation
          id={`pa-${annotation[0]}-${annotation[1]}`}
          key={`pa-${annotation[0]}-${annotation[1]}`}
          coordinate={annotation}
        />
      ))}
    </View>
  )
 }
}

class ChildA extends React.Component {
  render () {
    return (
      <ShapeSource id="circleLayer">
        <CircleLayer id="circleLayer" />
      </ShapeSource>
    )
  }
}

Expected behavior
The PointAnnotations should be displaying at the specified coordinates.

Actual behavior
The PointAnnotations which are added to the MapView after its mounting are displayed in the top left corner of the screen.

Screenshots
If applicable, add screenshots to help explain your problem.

Versions

  • Platform: iOS
  • Platform OS: iOS 15.5
  • Device: iPhone 13
  • Emulator/ Simulator: no
  • Dev OS: OSX 12.2.1 Monterey
  • @rnmapbox/maps Version 8.5.0
  • Mapbox GL
  • React Native Version 0.66.4

Additional context
I have dug into the underlying iOS code and found that the newly added PointAnnotation is never added to the MapView's (RCTMGLMapView.m) _pointAnnotations member. In pseudo code (though with accurate member function names), the process by which a PointAnnotation is added to the map seems to be the following:

PointAnnotation->setMap
MapView->addToMap (called within the above setMap, adds the PA to _pointAnnotations)
MapView->insertReactSubview
RCTSetChildren

NONE of the above functions are called when a PointAnnotation is added to the MapView after the MapView's initial rendering.

bwiitttyyyyy avatar Jul 22 '22 02:07 bwiitttyyyyy

+1 and when you move and zoom out the map it's going to move like crazy

lockieluke avatar Jul 25 '22 16:07 lockieluke

@lockieluke I have not experienced this

bwiitttyyyyy avatar Jul 26 '22 16:07 bwiitttyyyyy

+1 experiencing the same issue with PointAnnotations appearing in the top left

jwilles avatar Jul 26 '22 16:07 jwilles

@bwiitttyyyyy thanks for the report, unfortunately we're not actively looking into legacy mapbox (< v10) issues. Pr's always wellcome.

mfazekas avatar Jul 29 '22 13:07 mfazekas

@mfazekas This report sounds very much like the behavior from https://github.com/rnmapbox/maps/issues/2115, so I don't think it's safe to assume this is only a pre v10 issue.

michaek avatar Sep 07 '22 14:09 michaek

@mfazekas Was there a change that closed this, or was it closed as a duplicate of #2115? The reason I called attention to this issue, is that it appears to confirm that #2115 should be reopened.

michaek avatar Sep 16 '22 12:09 michaek

@michaek I could not reproduce using this modified example bellow on v10, but not sure as no annotation appeared at all for me. If the issue still there please report with a complete example like bellow.

import React from 'react';
import { View } from 'react-native';
import {
  MapView,
  ShapeSource,
  LineLayer,
  CircleLayer,
  PointAnnotation,
  Camera,
} from '@rnmapbox/maps';

const features = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      id: 'a-feature',
      properties: {
        icon: 'example',
        text: 'example-icon-and-label',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.00597, 40.71427],
      },
    },
    {
      type: 'Feature',
      id: 'b-feature',
      properties: {
        text: 'just-label',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.001097, 40.71527],
      },
    },
    {
      type: 'Feature',
      id: 'c-feature',
      properties: {
        icon: 'example',
      },
      geometry: {
        type: 'Point',
        coordinates: [-74.00697, 40.72427],
      },
    },
  ],
};

class App extends React.Component {
  render() {
    const coordinates = [
      [Math.random() * 360 - 180, Math.random() * 180 - 90],
      [Math.random() * 360 - 180, Math.random() * 180 - 90],
      [Math.random() * 360 - 180, Math.random() * 180 - 90],
      [Math.random() * 360 - 180, Math.random() * 180 - 90],
      [Math.random() * 360 - 180, Math.random() * 180 - 90],
      [Math.random() * 360 - 180, Math.random() * 180 - 90]
    ];

    // <Camera centerCoordinate={[-74.00597, 40.71427]} zoomLevel={14} />
    return (
      <MapView style={{ flex: 1 }}>
        <ChildA />
        <ChildB annotations={coordinates} />
      </MapView>
    );
  }
}

class ChildB extends React.Component {
  render() {
    const { annotations } = this.props;
    return (
      <View>
        {annotations.map((annotation) => (
          <PointAnnotation
            id={`pa-${annotation[0]}-${annotation[1]}`}
            key={`pa-${annotation[0]}-${annotation[1]}`}
            coordinate={annotation}
          />
        ))}
      </View>
    );
  }
}

class ChildA extends React.Component {
  render() {
    return (
      <ShapeSource id="circleLayer" shape={features}>
        <CircleLayer
          id="circleLayer"
          style={{ circleColor: '#ff0000', circleRadius: 10.0 }}
        />
      </ShapeSource>
    );
  }
}

export default App;

mfazekas avatar Sep 16 '22 16:09 mfazekas

That makes sense, @mfazekas. My interest is in getting #2115 reopened, since its example still reproduces the issue.

michaek avatar Sep 16 '22 17:09 michaek

@michaek I could not reproduce #2115 anymore. Tested on iOS. Which version have you tested?!

image

mfazekas avatar Sep 16 '22 21:09 mfazekas

Were you testing the original report template, or the updated template to show that the same issue was present when state caused the view to re-render? https://github.com/rnmapbox/maps/issues/2115#issuecomment-1216343341 I have tested and reproduced this in iOS (15.6.1), in both simulator and physical device.

michaek avatar Sep 16 '22 21:09 michaek

@michaek Both worked me just fine. What is your rnmapbox/maps version? Pls make sure that both #2205 and #2203 present in your version.

cat io/Podfile.lock | grep rnmapbox 
- rnmapbox-maps (10.0.0-beta.38):

mfazekas avatar Sep 17 '22 06:09 mfazekas

@mfazekas I don't think I'll be able to test this one soon, but since my testing was prior to #2203 and you're not able to reproduce, I am happy to assume those changes addressed the underlying issue. Thanks for pointing out the relevant changes!

michaek avatar Sep 20 '22 15:09 michaek

In Mapbox version 10 on ios, PointAnnotations were also not working for me.

I was fetching a list of coordinates async and mapping them onto the mapview directly in the return statement of my component.

The only way I could get it working on ios is the below example. In addition, without the custom View in the PointAnnotation children, it doesn't render anything at all.

Hope this helps someone else.

const renderAnnotations = useCallback(() => {
    return courts.map((court) => {
      return (
        <PointAnnotation
          key={court.id}
          id={court.id}
          coordinate={[court.lng, court.lat]}>
          <View style={{
                    height: 30, 
                    width: 30, 
                    backgroundColor: '#00cccc', 
                    borderRadius: 50, 
                    borderColor: '#fff', 
                    borderWidth: 3
                  }} />
          <Callout title={court.parkName} />
        </PointAnnotation>
      );
    });
  },[courts]);
  
  return (
    <View style={styles.container}>
      <ActivityIndicator style={styles.loading} color='white' />
      <MapView
        style={{ flex: 1 }}
        styleURL={StyleURL.Dark}
        attributionEnabled={false}>
        {renderAnnotations()}
        <Camera
          centerCoordinate={//@ts-ignore
            userHomeCourtCoords.values}
          zoomLevel={12}
          followZoomLevel={14}
        />
        <UserLocation
          animated={true}
          showsUserHeadingIndicator={true}
        />
        
      </MapView>
    </View>
  );
};

5PK avatar Jan 18 '24 14:01 5PK