React-Native-Maps don't seem to rerender once the geo location is acquired
Asked Answered
Z

3

10

I'm trying to create a simple app that loads a google map (using airbnb's react-native-maps library) and shows the user's current location. What I'm seeing is that the map always shows the default initial position rather than re-rendering once the user's location is acquired.

I'm using React 0.42 and testing only on iOS. Here is some code to clarify:

1.) I set an initial state

state = {
      region: {
        latitude: 52,
        longitude: 5,
        latitudeDelta: 0.0922,
        longitudeDelta: 0.0421
      }
  }

2.) I get the user's location within componentDidMount

componentDidMount() {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        this.setState({
          region: {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            latitudeDelta: 0.01,
            longitudeDelta: 0.0011
          }
        });
      },
      (error) => alert(JSON.stringify(error)),
      {enableHighAccuracy: true, timeout: 20000, maximumAge: 1000}
    );
  }

3.) With render, I display the map with the initial region, and expect that region to change once the user's location is acquired

render() {
    return (
     <View style={{ flex: 1 }}>
       <View style={{backgroundColor: 'coral', height: 70, justifyContent: 'center', alignItems: 'center'}}>
         <Text>
            <Text>longitude: {this.state.region.longitude}</Text>
            <Text>latitude: {this.state.region.latitude}</Text>
        </Text>
       </View>
       <View style={styles.container}>
         <MapView
           provider={PROVIDER_GOOGLE}
           style={styles.map}
           initialRegion={this.state.region}
           region={this.state.region}
           onRegionChange={this.onRegionChange}
           onRegionChangeComplete={this.reloadEntities}
         />
       </View>
     </View>
   );
 }

Here is the onRegionChange, just updates the state with the new region, which I believe will cause a re-render

onRegionChange = (region) => {
  this.setState({ region });
}

NOTE: The longitude and latitude text values do update as the region on the map changes, and they have they are updated once the user's location is acquired.

So I'm a bit confused as to why the map does not change what it's showing once the user's location is acquired. Any help would be much appreciated!

Update: I've taken a look at this thread: https://github.com/airbnb/react-native-maps/issues/43 and it seems to revolve mainly around Android, but I did try to remove the enableHighAccuracy option with no luck.

Zacharia answered 9/3, 2017 at 3:48 Comment(0)
S
0

It's also important to get rid of onRegionChangeComplete={this.reloadEntities}.

Every time the region changes, react-native will reload and default back to the initial state you declared in your constructor.

Snowclad answered 14/3, 2017 at 10:41 Comment(1)
Thanks, this seems to do the trick, as I noted in another comment, how else can you invoke a callback function after the region change is complete?Zacharia
L
3

Set the region of the MapView with the value of your region state this.state.region.

You need to get the current position and setting it to the region and then to use the watchPosition function to get the coordinates everytime the device detects there's a change in the location, this time set the new values to your region state.

This would work this way

import React, { Component } from 'react';
import MapView from 'react-native-maps';
import { AppRegistry, View } from 'react-native';

const { width, height } = Dimensions.get('window');
const ASPECT_RATIO    = width / height;
const LATITUDE        = 37.78825;
const LONGITUDE       = -122.4324;
const LATITUDE_DELTA  = 0.0122;
const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
const SPACE           = 0.01;

class Test extends Component {
  constructor() {
    super();
    this.state = {
      region: {
        latitude: LATITUDE,
        longitude: LONGITUDE,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA
      }
    }
  }

componentDidMount() {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        this.setState({
          region: {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            latitudeDelta: LATITUDE_DELTA,
            longitudeDelta: LONGITUDE_DELTA,
            accuracy: position.coords.accuracy
          }
        });
      },
      (error) => alert(error.message),
      {timeout: 10000}
    );

    this.watchID = navigator.geolocation.watchPosition((position) => {
      const newRegion = {
        latitude: position.coords.latitude,
        longitude: position.coords.longitude,
        latitudeDelta: LATITUDE_DELTA,
        longitudeDelta: LONGITUDE_DELTA,
        accuracy: position.coords.accuracy
      }
      this.setState({newRegion});
    });
  }

  componentWillUnmount() {
    navigator.geolocation.clearWatch(this.watchID);
  }

  render() {
    return (
      <View style={styles.container}>
        <MapView
          style={styles.map}
          region={this.state.region}
          showsUserLocation={true}
          followUserLocation={true}>
        </MapView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'flex-end',
    alignItems: 'center',
  },
  map: {
    ...StyleSheet.absoluteFillObject,
  },
});

AppRegistry.registerComponent('Russia terrorist state', () => Test);

Be sure to enable showsUserLocation and followUserLocation in the MapView, this way the app will ask the user current location.

followUserLocation depends on showUserLocation.

Constant longitude and latitude are only as example.

Liter answered 10/3, 2017 at 13:58 Comment(4)
Thanks! This has helped with understanding some additional options on the MapView. However, it seems @Adam-Patterson's suggestion of removing onRegionChangeComplete consistently shows the proper location. That being said, how else can you invoke a callback function after the region change is complete?Zacharia
@Zacharia glad to help you, as it says, onRegionChangeComplete is already a callback that's called once when the region changes, such as when the user is done moving the map, so, you could override its behavior adding the logic that you need in it. akshay2604 has opened an issue on the react-native-maps repository that maybe could help you github.com/airbnb/react-native-maps/issues/846Dwinnell
Perfect, thank you! Seems like I was running into that same issue even on iOS. I'll add to that issues thread with some additional info. Thanks again!Zacharia
Correct spelling is followsUserLocation not followUserLocationMadson
R
2

You should not use initialRegion prop with region prop together:

Use this prop instead of region only if you don't want to control the viewport of the map besides the initial region.

Source

It should work after you remove the initialRegion prop.

Radiculitis answered 9/3, 2017 at 19:5 Comment(0)
S
0

It's also important to get rid of onRegionChangeComplete={this.reloadEntities}.

Every time the region changes, react-native will reload and default back to the initial state you declared in your constructor.

Snowclad answered 14/3, 2017 at 10:41 Comment(1)
Thanks, this seems to do the trick, as I noted in another comment, how else can you invoke a callback function after the region change is complete?Zacharia

© 2022 - 2024 — McMap. All rights reserved.