Search code examples
react-nativereact-native-maps

'react-native-maps' becomes extremely slow after adding new marker


I am totally stumped by this problem.

First off this bug only happens in the Android release version of my app. Doesn't seem to affect iOS and I can't reproduce it in debug.

From package.json:

"react-native": "0.62.2",
"react-native-maps": "0.27.1",

I have a map that renders non-customised markers for nearby events. Everything is smooth until a user adds a new event. The event gets added to the server, the app syncs with the server, and the new event is added to the state in Redux. If I switch back to the map view after creating the event then I can see the new marker, but now if I move the map around it's incredibly jerky.

I've spent a couple of days trying to figure this out, and some things I've noticed are:

  • It only happens about 80% of the time after adding new events.
  • If I background the app and open it again then the map moves smoothly again.
  • If I delete the event I just added, the marker gets removed and the map is smooth.
  • I logged renders of my map component, and there's nothing unusual about the number of renders (i.e. it's not trying to re-render on every region change or anything weird like that).
  • I tried clearing all events before syncing with the server (and hiding all markers during the refresh). Doesn't solve the problem.

Suggested solutions I've tried from other posts that haven't fixed the problem/were already implemented:

  • Markers already have prop tracksViewChanges={false}
  • Removing onRegionChange from the Map props
  • Removing the transparent overlay I had for various buttons, plus other map components (Polygon).

Relevant code

     // Map.ts

     <View style={styles.container}>
        {/* <Banner bannerState={bannerState} text={bannerText} /> */}
        <MapView
          showsUserLocation
          rotateEnabled={false}
          pitchEnabled={false}
          moveOnMarkerPress={false}
          showsMyLocationButton={false}
          showsTraffic={false}
          showsIndoors={false}
          style={styles.map}
          onRegionChange={this.onRegionChange}
          onRegionChangeComplete={this.onRegionChangeComplete}
          onPoiClick={this.onPoiClick}
          initialRegion={this.initialRegion}
          region={region}
        >
           <ItemMarkers
             shouldUseDetailedMarkers
             key='ITEM_MARKERS'
             items={items}
             makeOnPress={this.makeOnPressItem}
           />
        {/* {this.HighlightedArea()} */}
        </MapView>
      </View>
    const ItemMarkers = (props: {
      items: IMapItem[];
      makeOnPress: (index: number) => VoidFunction;
    }): JSX.Element => {
      const {items, makeOnPress} = props;
    
      const renderMarker = (mapItem: IMapItem, index: number) => {
        const {
          description,
          key,
          title,
          location: {latitude, longitude},
        } = mapItem;
    
        return (
          <DefaultMarker
            key={key}
            latitude={latitude}
            longitude={longitude}
            title={title}
            description={description}
            onPress={makeOnPress(index)}
          />
        );
      };
    
      return <View key='ITEM_MARKERS'>{items.map(renderMarker)}</View>;
    };
    // Marker component that gets rendered within DefaultMarker

    <Marker
      key={props.key}
      stopPropagation
      style={styles.marker}
      identifier={props.key}
      tracksViewChanges={false}
      coordinate={{ latitude, longitude }}
      onPress={props.onPress}
    / >

Let me know if there's other code you'd like to see, and thanks in advance! I don't know what else to try.


Solution

  • I found a very 'hacky' way around the problem... I give a key to <Map... / > which is tied to the number of events created in the session (i.e. key={MAP_KEY_${numCreatedEvents}}`. This essentially forces the map to completely refresh when new events are added by the user.

    It's not a great solution, but it solves my immediate problem. Will mark this as accepted unless someone can suggest something more elegant.