MapView的onRegionChange回调的不稳定行为

时间:2018-03-23 17:29:16

标签: reactjs react-native redux expo react-native-maps

希望你没事。

现在正确,我遇到了react-native-mapsexporedux

的MapView组件问题

onRegionChange / onRegionChangeComplete 道具行为迟钝且不稳定,我无法找出原因。

  

我已经录制了3段非常短的视频,我希望你能看到,你会   了解所有这些。

您可以在此处看到此行为:https://youtu.be/HvKiC838ZiQ

我怎么到这里来?后续。

首先,我想创建一个允许我实现3件事的组件:

  1. 从设备获取位置并将其设置为适合区域的组件状态
  2. onLongPress
  3. 时添加自定义图像标记
  4. onPress
  5. 时,在标记周围绘制一个多边形以划分该标记的区域

    为实现这一目标,我决定从第2点开始。 3,一旦完成,询问位置。

    所以我写了这个:

    这是汇总的redux组件状态:

    const INITIAL_STATE = {
     initialRegion: {
      latitude: 3.4562823396110987,
      longitude: -76.53087161634343,
      longitudeDelta: 0.020077778360303,
      latitudeDelta: 0.02730640974786524,
     },
     region: {
      latitude: null,
      longitude: null,
      longitudeDelta: null,
      latitudeDelta: null
      },
    

    }

    这是我写过的mapComponent:

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import { View, TouchableOpacity, Image, Platform, Constants } from 'react-native';
    import { Ionicons } from '@expo/vector-icons';
    import { MapView, Location, Permissions } from 'expo';
    import { setCurrentLocation, handlerRegion } from '../actions';
    
    class Map extends Component {
      renderMarker = () => {
        if (this.props.direccion) {
          return (
            <MapView.Marker
              draggable
              coordinate={this.props.direccion}
            >
            <Image
              source={require('../images/LocationIcon.png')}
              style={{ width: 37, height: 56 }}
            />
            </MapView.Marker>
          );
        }
      }
    
      render() {
        const { mapStyle, buttonContainerStyle, trashButtonStyle } = styles;
        const TrashButton = (props) => {
          if (this.props.polygon.length > 0) {
            return (
              <TouchableOpacity onPress={props.trash}>
                <View style={trashButtonStyle}>
                    <Ionicons name="ios-trash" size={35} color="#eb4050" />
                </View>
              </TouchableOpacity>
            );
          }
          return null;
        };
        return (
          <View style={{ flex: 1 }}>
            <MapView
              style={mapStyle}
              initialRegion={this.props.initialRegion}
              onPress={this.props.onPress}
              onLongPress={this.props.onLongPress}
            >
                <MapView.Polygon
                  coordinates={this.props.polygon}
                  fillColor="rgba(235, 64, 80, 0.5)"
                  strokeColor="rgba(235, 64, 80, 1)"
                  holes={this.props.holes}
                  geodesic
                  lineDashPhase={6}
                  strokeWidth={2}
                />
                {this.renderMarker()}
            </MapView>
            <View style={buttonContainerStyle}>
              <TrashButton trash={this.props.trashButton} />
            </View>
          </View>
        );
      }
    }
    
    const styles = {
        //Extracted for conciseness
    };
    
    const mapStateToProps = state => {
      return {
        polygon: state.perfil.polygon,
        region: state.perfil.region,
        direccion: state.perfil.direccion,
        initialRegion: state.perfil.initialRegion
      };
    };
    
    export default connect(mapStateToProps, { setCurrentLocation, handlerRegion })(Map);
    

    这是parentComponent,它具有设置标记,多边形等方法:

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import { View } from 'react-native';
    import { MapView } from 'expo';
    import { Header } from '../common';
    import {
      setRestaurantLocation,
      setPolygonPoint,
      setHoles,
      eraseDeliveryArea,
      saveRestaurantAddress,
      setCurrentLocation,
      handlerRegion
    } from '../actions';
    import Maps from './Maps';
    
    class DireccionRestaurant extends Component {
      static navigationOptions = {
        drawerLockMode: 'locked-closed',
      }
    
      saveRestaurantAddressHandler = () => {
        const { direccion, polygon, user } = this.props;
        this.props.saveRestaurantAddress(direccion, polygon, user);
        this.props.navigation.goBack();
      }
    
      setRestaurantLocationHandler = (latLng) => {
        if (!this.props.direccion) {
          this.props.setRestaurantLocation(latLng);
        }
      }
    
      setPolygonPointHandler = (latLng) => {
        if (this.props.direccion) {
          this.props.setPolygonPoint(latLng);
        }
      }
    
      setHolesHandler = (latLng) => {
        console.log('this is the obj: ', latLng);
        this.props.setHoles(latLng);
      }
    
      eraseDeliveryAreaHandler = () => {
        this.props.eraseDeliveryArea();
      }
    
      render() {
        const { navigation } = this.props;
        return (
          <View style={{ flex: 1 }}>
            <Header title="Direccion" type="back" button="Guardar" onPress={() => this.saveRestaurantAddressHandler()} backLink={() => navigation.goBack()} />
            <Maps
              onPress={(e => this.setPolygonPointHandler(e.nativeEvent.coordinate))}
              onLongPress={(e => this.setRestaurantLocationHandler(e.nativeEvent.coordinate))}
              trashButton={() => this.eraseDeliveryAreaHandler()}
            />
          </View
        );
      }
    }
    
    const mapStateToProps = state => {
      return {
        polygon: state.perfil.polygon,
        holes: state.perfil.holes,
        direccion: state.perfil.direccion,
        user: state.auth.user,
        region: state.perfil.region,
      };
    };
    
    export default connect(mapStateToProps, {
      setPolygonPoint,
      setHoles,
      setRestaurantLocation,
      eraseDeliveryArea,
      saveRestaurantAddress,
      setCurrentLocation,
      handlerRegion 
    })(DireccionRestaurant);
    

    通过此设置,我实现了第2点和第2点。 3。 你可以在这里看到:

    https://www.youtube.com/watch?v=W7f8wpkiYjo

    好的,现在所有人似乎都按预期工作了,我微笑着去寻找1个目标:询问设备位置......

    我决定使用AirBNB的expo react-native-maps实现,所以我将此道具添加到我的Maps.js组件中:

    //class Map extends Component {
    getLocationAsync = async () => {
       // let { status } = await Permissions.askAsync(Permissions.LOCATION);
       //if (status !== 'granted') {
       // this.setState({
       //   errorMessage: 'Permission to access location was denied',
       // });
       // }
    
        let location = await Location.getCurrentPositionAsync({});
        const latitude = location.coords.latitude;
        const longitude = location.coords.longitude;
    
        this.props.setCurrentLocation(latitude, longitude);
        console.log('this is the latitude mounted: ', latitude, '- this the longitude: ', longitude);
      };
    //...
    

    我还写了生命周期方法:

    //class Map extends Component {
    //...
      componentWillMount() {
        this.getLocationAsync();
      }
    //...
    

    因此,当componentWillMount请求位置并使用此流程将位置设置为新状态时:

    动作

    export const setCurrentLocation = (latitude, longitude) => {
      const newState = {
        latitude,
        longitude,
        latitudeDelta: 0.026541072889699535,
        longitudeDelta: 0.019344975439523182,
      };
      return {
        type: SET_ACTUAL_LOCATION,
        payload: newState
      };
    };
    

    减速

    case SET_ACTUAL_LOCATION:
        return { ...state, region: action.payload };
    

    并更新了地图组件:

    <MapView
     style={mapStyle}
     initialRegion={this.props.initialRegion}
     region={this.props.region}// <--- Added this
     onPress={this.props.onPress}
     onLongPress={this.props.onLongPress}
    >
    

    万岁!位置正在工作,让我们添加标记......什么?...发生了什么?好吧,也许只是我。让我们尝试创建多边形......什么?它又发生了!

    观看此视频,了解发生了什么:https://youtu.be/RlKZvBTVXa0

    我想:

      

    哦! ,这似乎是由于没有onRegionChange引起的   方法,因为当我把一个新的标记或添加一个新的点,所以   组件重新呈现与存储在其上的最后一个区域   州。好的,所以我会添加一个onRegionChangeComplete,因为它适合   更符合我的需求。

    现在我将它添加到Maps.js组件:

    <MapView
        style={mapStyle}
        initialRegion={this.props.initialRegion}
        region={this.props.region}
        onPress={this.props.onPress}
        onLongPress={this.props.onLongPress}
        onRegionChangeComplete={(region) => this.props.handlerRegion(region)}//<-ADDED THIS
    >
    

    并编写以下redux流程:

    动作:

    export const handlerRegion = (region) => {
      return {
        type: HANDLE_CHANGE_REGION,
        payload: region
      };
    };
    

    减速

    case HANDLE_CHANGE_REGION:
          return { ...state, region: action.payload };
    

    Aaaaaand ......结果是在第一个视频中发生了什么。 这是视频 - &gt;:https://youtu.be/HvKiC838ZiQ

    该组件完全正常工作。现在存储在状态中的最后一个区域与我们搜索的位置相同,所以当我添加一个标记或多边形的点时,它仍然保留在应该的位置。 剩下的唯一问题是你可以看到的滞后和奇怪的行为......

    我认为它可能是由redux引起的,所以我尝试使用reactComponent的状态,但它也发生了。

    我尝试使用onRegionChange和onRegionChangeComplete,但它几乎相同。

    我用同样的问题搜寻了其他人,但我没有找到任何问题。

    我无法弄清楚为什么会这样。 你知道为什么吗?

1 个答案:

答案 0 :(得分:0)

initialRegion设置为MapView并删除region = {this.state.region}对我来说解决了类似的问题。