当onRegionChange时,React Native Maps调用api请求

时间:2019-03-11 20:34:47

标签: google-maps react-native

我正在使用React本机地图,并在地图上显示业务标记。 我想调用api以根据新坐标获得新的领导能力。 我想做的是在事件“ onRegionChangeComplete”上调用api,它可以正常工作并在地图上显示新标记,但是我有一些问题:

  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 个答案:

答案 0 :(得分:1)

鉴于API如此频繁地/每次加载标记时都会被调用,因此我对您的地图运行缓慢并不感到惊讶。

[减少api调用]可行的解决方案是创建一种标记的“区域缓存”,这样就无需再次查询以前加载的标记。

来自Four tips to Optimize Your Map with 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。然后,您可以使用控件指定仅当标记的ID被选中/未选中/已被缩放/缩放等时才希望渲染标记。

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

如果您有很多不需要显示的标记,则可以考虑使用“ clustering”,它会将不需要显示的标记束“分组”为一个大标记[如相对于许多小型应用程序而言],但从您的应用程序描述来看,我认为这并不特别适合您。

最后,我想回顾一下您的代码,以确保您的标记不会执行不必​​要的计算:如果您可以将prop作为参数传递,这将减少处理时间并提高性能!

希望这会有所帮助

[逐个,我发现this piece of code,它加载了许多标记,我认为您可能会感兴趣。但是请考虑以上几点!]