Реагировать на запрос вызова API собственных карт, когда onRegionChange - PullRequest
2 голосов
/ 11 марта 2019

Я использую нативные карты реагирования и показываю на карте бизнес-маркеры. Я хочу позвонить в API, чтобы получить новое руководство в соответствии с новыми координатами. я пытаюсь вызвать api для события onRegionChangeComplete, он работает и показывает новые маркеры на картах, но у меня есть некоторые проблемы:

  1. карты работают очень медленно и требуют времени, чтобы загрузить карту (новые улицы и загрузить карту)
  2. даже я использовал debounce для вызова onRegionChangeComplete, он вызывает api каждый раз и выглядит не очень хорошо.
  3. , когда я двигаюсь с картой, я ухожу на первое место

код

import React, { Component } from 'react'
import { View, Text, FlatList } from 'react-native'
import { inject, observer } from 'mobx-react/native'
import style from './style'
import I18n from '../../i18n'
import Icon from 'react-native-vector-icons/Feather'
import MapView, { PROVIDER_GOOGLE, Marker } from 'react-native-maps' // remove PROVIDER_GOOGLE import if not using Google Maps
import { BusinessDetailItem } from '../../components'
import { calcSize } from '../../utils'
import Colors from '../../utils/Colors'
import _ from 'lodash'

import MapView, { PROVIDER_GOOGLE, Marker } from 'react-native-maps' 

@inject('UserStore')
@observer
class BusinessMap extends Component {
  constructor(props) {
    super(props)
    this.state = {
      details: {},
      region: {
        latitude: props.UserStore.Latitude,
        longitude: props.UserStore.Longitude,
        latitudeDelta: Math.abs(props.UserStore.Latitude / 5000),
        longitudeDelta: Math.abs(props.UserStore.Longitude / 5000),
      },
    }

    this.debounce = _.debounce(data => this.onRegionChangeComplete(data), 1000)
  }

  componentDidMount() {}

  renderUserMarker = () => {
    const { UserStore } = this.props
    return <MapView.Marker tracksViewChanges={false} coordinate={{ latitude: UserStore.Latitude, longitude: UserStore.Longitude }} title={I18n.t('my_location')} />
  }

  renderBusinessMarkers = () => {
    const { UserStore } = this.props
    if (UserStore.orgs.length > 0) {
      return UserStore.orgs.map((info, i) => (
        <MapView.Marker
          tracksViewChanges={false}
          key={i}
          coordinate={{ latitude: info.location.coordinates[1], longitude: info.location.coordinates[0] }}
          title={info.org_name}
          onCalloutPress={() => {
            this.props.navigation.navigate('BusinessDetail', { org_id: info._id })
          }}
        />
      ))
    }
    return null
  }


  onRegionChangeComplete = region => {
    this.setState({ region })
    let query = {
      lat: region.latitude,
      lng: region.longitude,
      limit: 10,
    }
    await this.props.UserStore.getOrgsByLocation(query)

    console.log('onRegionChangeComplete', region)
  }
  renderMap = () => {
    console.log('this.state.region', this.state.region)
    const { UserStore } = this.props
    return (
      <View style={style.view_address_map}>
        <View style={style.view_map}>
          <MapView
            // scrollEnabled={false}
            showsUserLocation
            followUserLocation
            toolbarEnabled={false}
            showsIndoors={false}
            moveOnMarkerPress={false}
            style={style.map}
            region={this.state.region}
            onUserLocationChange={e => {
              'onUserLocation', console.log(e.nativeEvent)
            }}
            onPress={() => {
              console.log('onPres')
            }}
            onCalloutPress={e => {
              'onCalloutPress', console.log(e.nativeEvent)
            }}
            onRegionChange={this.onRegionChange}
            onRegionChangeComplete={this.onRegionChangeComplete}
          >
            {this.renderUserMarker()}
            {this.renderBusinessMarkers()}
          </MapView>
        </View>
      </View>
    )
  }
  renderBusinessDetailItem = (appointment, index) => {
    return <BusinessDetailItem {...appointment.item} navigation={this.props.navigation} addToFavouriteList={() => {}} />
  }

  renderBusinessList = () => {
    return (
      <View style={style.view_flat_last_minute_appointments}>
        <FlatList
          horizontal={true}
          disableVirtualization={true}
          contentContainerStyle={style.view_content_container_flat_list_last_minutes}
          data={this.props.UserStore.orgs}
          keyExtractor={(item, index) => `key-${index}`}
          renderItem={this.renderBusinessDetailItem}
          // ListEmptyComponent={this.renderEmptyComponent}
          showsHorizontalScrollIndicator={false}
          style={style.content_flat_list}
        />
      </View>
    )
  }

  render() {
    const { container, view_close_icon, icon_close } = style
    const { coordinates } = this.state.details
    const { UserStore } = this.props
    return (
      <View style={container}>
        <View style={view_close_icon}>
          <Icon
            name='x'
            size={calcSize(60)}
            color={Colors.black}
            style={icon_close}
            onPress={() => {
              this.props.navigation.goBack()
            }}
          />
        </View>
        {UserStore.orgs && this.renderMap()}
        {this.renderBusinessList()}
      </View>
    )
  }
}

export default BusinessMap

1 Ответ

1 голос
/ 16 марта 2019

Я не удивлен, что ваша карта работает медленно, учитывая, что API вызывается так часто / каждый раз, когда вы загружаете маркер.

Одним из жизнеспособных решений [для сокращения вызовов API] было бы создать своего рода «кэш области» маркеров, чтобы не нужно было снова запрашивать ранее загруженные маркеры.

Из Четыре совета по оптимизации вашей карты с помощью React Native:

Эффективный способ уменьшить количество звонков, которые вам нужно сделать, - это создать локальный кеш.Например, перед каждым запросом создайте ключ с параметрами (тип poi, описание и т. Д.) Вашего запроса и сохраните его в состоянии рядом с запрашиваемой областью.Это можно сделать следующим образом:

Пример кода:

const key = createKey({pinTypes, searchText});
this.setState({
    queriedRegion: {
        [key]: boundaries(region)
    },
    businessMarkers,
})

Кэшируя уже запрошенные точки, затем перед извлечением новых точек вы можете проверить, был ли выполнен последний вызов.с тем же ключом и с областью, охватывающей текущий.Если это так, вы знаете, что у вас уже есть все точки, которые вы хотели отобразить, и что вы можете спокойно игнорировать этот запрос (учитывая, что вы всегда запрашиваете все точки в пределах области, которые соответствуют критерию, и вы не фильтруете в зависимости от уровня масштабирования).

if(
   this.state.queriedRegion &&
   this.state.queriedRegion[key] &&
   isRegionWithin(boundaries(region), this.state.queriedRegion[key])
) {
    //Do not query the points, they are already fetched !
    return;
}

Другим способом предотвращения ненужных визуализаций карты было бы использование shouldComponentUpdate в вашем пользовательском классе маркера.Затем у вас есть элемент управления, чтобы указать, что вы хотите, чтобы ваш маркер отображался только в том случае, если его идентификатор выбран / не выбран / больше / увеличен и т. Д.

shouldComponentUpdate(prevProps) {
    return prevProps.isSelected !== this.props.isSelected ||
           prevProps.isZoomed !== this.props.isZoomed}

Если у вас много маркеров, которые могут не понадобитьсяпоказано, что вы могли бы рассмотреть « кластеризацию », которая «группирует» группы не нужных для показа маркеров вместе в один большой маркер [в отличие от множества маленьких], но из описанияваше приложение, я не думаю, что это особенно применимо к вам.

Наконец, я бы сказал, чтобы проверить ваш код, чтобы убедиться, что ваши маркеры не выполняют ненужных вычислений: если вы можете передавать реквизиты в качестве аргументов, этосократит время обработки и улучшит производительность!

Надеюсь, это поможет

[кстати, я нашел этот фрагмент кода , который загружает много маркеровЯ подумал, что это может вас заинтересовать.Но учти вышеизложенные пункты!]

...