React Native: как остановить повторный рендеринг маркеров карты при каждом обновлении состояния - PullRequest
2 голосов
/ 15 мая 2019

У меня есть компонент, который имеет карту с несколькими пользовательскими маркерами для разных мест и карусель с картами для тех же мест. Когда пользователь нажимает маркер, он должен отображать выноску и показывать имя местоположения рядом с маркером (но вне выноски).

Однако, поскольку я обновляю состояние в onRegionChangeComplete, если пользователь перемещает карту, а затем быстро нажимает маркер (до того, как состояние заканчивает обновление после вызова setState в onRegionChangeComplete), то маркеры будут повторно рендер до запуска события onPress, и событие никогда не запускается.

Одним из решений может быть использование shouldComponentUpdate, однако в документации указано, что его следует использовать только для оптимизации производительности, а не для предотвращения повторного рендеринга (https://reactjs.org/docs/react-component.html#shouldcomponentupdate),, но, что более важно, моя componentDidUpdate функция имеет некоторую условную логику, зависящую от региона, установленного в shouldComponentUpdate, а также другие условные действия, поэтому я не хочу предотвращать повторную визуализацию всего компонента, просто ненужную повторную визуализацию маркеров.

Я также использую оптимизацию производительности, упомянутую в https://github.com/react-native-community/react-native-maps/issues/2082, оборачивая создатели в компонент, который реализует shouldComponentUpdate и getDerivedStateFromProps, однако я не совсем уверен, что это что-то делает, потому что это похоже, что родительский компонент просто воссоздает все мои оптимизированные маркеры, а не использует их оптимизации для обработки повторного рендеринга. Кроме того, даже если я не использую маркер с оберткой, а обычный маркер, у меня все равно остаются те же проблемы.

Я также открыл проблему для этого на реагирующих нативных картах, но еще не получил ответа: https://github.com/react-native-community/react-native-maps/issues/2860

Моя функция onRegionComplete, которая обновляет состояние при перемещении карты. Для краткости я удалил несколько других обновлений условного состояния:

onRegionChangeComplete = (region) => {
    const nextState = { };
    nextState.region = region;

    if (this.state.showNoResultsCard) {
      nextState.showNoResultsCard = false;
    }

    .
    .
    .

    this.setState({ ...nextState });

    this.props.setSearchRect({
      latitude1: region.latitude + (region.latitudeDelta / 2),
      longitude1: region.longitude + (region.longitudeDelta / 2),
      latitude2: region.latitude - (region.latitudeDelta / 2),
      longitude2: region.longitude - (region.longitudeDelta / 2)
    });
  }

MapView с использованием более обычного маркера (не оптомизированной версии):

<MapView // show if loaded or show a message asking for location
    provider={PROVIDER_GOOGLE}
    style={{ flex: 1, minHeight: 200, minWidth: 200 }}
    initialRegion={constants.initialRegion}
    ref={this.mapRef}
    onRegionChange={this.onRegionChange}
    onRegionChangeComplete={this.onRegionChangeComplete}
    showsUserLocationButton={false}
    showsPointsOfInterest={false}
    showsCompass={false}
    moveOnMarkerPress={false}
    onMapReady={this.onMapReady}
    customMapStyle={mapStyle}
    zoomTapEnabled={false}
    >

        {this.state.isMapReady && this.props.places.map((place, index) => {
            const calloutText = this.getDealText(place, 'callout');
            return (
                <Marker
                    tracksViewChanges
                    key={Shortid.generate()}
                    ref={(ref) => { this.markers[index] = ref; }}
                    coordinate={{
                        latitude: place.getLatitude(),
                        longitude: place.getLongitude()
                    }}
                    onPress={() => { this.onMarkerSelect(index); }}
                    anchor={{ x: 0.05, y: 0.9 }}
                    centerOffset={{ x: 400, y: -60 }}
                    calloutOffset={{ x: 8, y: 0 }}
                    calloutAnchor={{ x: 0.075, y: 0 }}
                    image={require('../../Assets/icons8-marker-80.png')}
                    style={index === this.state.scrollIndex ? { zIndex: 2 } : null}
                >
               {this.state.scrollIndex === index &&
                    <Text style={styles.markerTitle}>{place.getName()}</Text>}

                  <Callout onPress={() => this.onCalloutTap(place)} tooltip={false}>
                    <View style={{
                      borderColor: red,
                      width: 240,
                      borderWidth: 0,
                      borderRadius: 20,
                      paddingHorizontal: 8,
                      flexDirection: 'column',
                      justifyContent: 'flex-start',
                      alignItems: 'center'
                    }}
                    >
                      <Text style={styles.Title}>Now:</Text>
                      <View style={{
                        width: 240,
                        flexDirection: 'column',
                        justifyContent: 'space-evenly',
                        alignItems: 'flex-start',
                        paddingHorizontal: 8,
                        flex: 1
                      }}
                      >
                        {calloutText.Text}
                    </View>
                </View>
            </Callout>
        </Marker>
        );
    }) 
}

</MapView>

Моя функция для события маркера на прессе:

onMarkerSelect(index) {
    this.setState({ scrollIndex: index });
    this.carousel._component.scrollToIndex({
      index,
      animated: true,
      viewOffset: 0,
      viewPosition: 0.5
    });

    this.markers[index].redrawCallout();
}

Обновление состояния и быстрое нажатие на маркер приведут к тому, что событие onPress не сработает. Кроме того, маркеры перерисовываются / воссоздаются каждый раз, когда обновляется родительский компонент. (Я говорю «воссоздано», потому что кажется, что маркеры перерисовываются без запуска даже shouldComponentUpdat e или componentDidUpdate).

Есть ли способ обновить состояние в onRegionChangeComplete без принудительного повторного рендеринга маркеров?

...