Search code examples
reactjsreact-nativereact-native-iosreact-native-listviewreact-native-maps

Getting an error when trying to update the state of region in React Native Mapview component using an onPress event


I am using React Native to create a map app for IOS mobile devises. I am using React Natives MapView component and I am trying to update the region using onRegionChange event within an onPress function so that when a user enters an address, the setState within the onRegionChange will render that address with a marker placed on the address entered by the user.

I have tried calling the on RegionChange function within my _addItem function onPress event. I pass in that function this.state.region in which I set equal to the coordinates of the marker using this.state.coordinate but I keep getting this error in the console:

Error: You attempted to set the key latitude with the value 33.77709834885268 on an object that is meant to be immutable and has been frozen.

I also tried making a new function called onMarkerChange and calling setState on the coordinates of the markers and then calling the onMarkerChange function within the _addItem functions onPress and I get the marker rendered on the new address input by the user but it takes me out of region and the user has to click on the marker several times to zoom back into region.

Can someone please tell me what I am doing wrong by taking a look at my code. Thanks so much!

Here is my code:

 class Map_app2 extends Component {

     constructor(props){
     super(props);

    this.state = {
        region: {
          latitude: 33.753746,
          longitude: -84.386330,
          latitudeDelta: 0.0922,
          longitudeDelta: 0.0121
      },

        coordinate: {
            latitude: 33.749249,
            longitude: -84.387314,
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0121
        },

        dataSource: new ListView.DataSource({
            rowHasChanged: (row1, row2) => row1 !== row2})
     };
    this.itemsRef = this.getRef().child('items');
    this.onRegionChange = this.onRegionChange.bind(this);
    this.onMarkerChange = this.onMarkerChange.bind(this);
}
onRegionChange(region){
    this.setState({region});
}
onMarkerChange(coordinate){
        this.setState({coordinate})
}
getRef(){
    return firebaseApp.database().ref();
}
listenForItems(itemsRef){
  itemsRef.on('value', (snap) => {
    var items = [];
    snap.forEach((child) =>{
       items.push({
         address: child.val()._address,
         _key: child.key
       });
       console.log(items)
   });

   this.setState({
    dataSource: this.state.dataSource.cloneWithRows(items),
    });

  });

}

 componentDidMount() {
    this.listenForItems(this.itemsRef);
  }

  render() {
        console.log(this.state.region);
      console.log(this.state.coordinate)

  return (

    <View style={styles.container}>
    <MapView
      style={styles.map}
      region={this.state.region}

      onRegionChange={this.onRegionChange}
    >

    <MapView.Marker
      coordinate={{ 
        latitude: this.state.coordinate.latitude,
        longitude: this.state.coordinate.longitude 
      }}
      onPress= {() => console.log(this.state.coordinate)}>

    </MapView.Marker>
        <ActionButton 
          onPress={this._addItem.bind(this)} 
          title="Search Address"/>

    </MapView>

     <ListView 
       dataSource= {this.state.dataSource} 
       renderRow= {this._renderItem.bind(this)}
       style= {styles.listview}
       enableEmptySections={true}>
       </ListView>

    </View>

   );
 }

 _addItem() {
    AlertIOS.prompt(
      'Look up address',
      null,
        [{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), 

                 style:'cancel'},

   {
      text: 'Enter',
      onPress: (value) => Geocoder.geocodeAddress(value).then(res => {
                // res is an Array of geocoding object (see below)

                        this.state.coordinate.latitude = res[0].position.lat 
                        this.state.coordinate.longitude = res[0].position.lng
                         this.state.region = this.state.coordinate

                        this.onRegionChange(this.state.region)
                        this.itemsRef.push({address: res[0].formattedAddress})

            })

               .catch(err => console.log(err)) 
     }],
     'plain-text'
   );
}

 _renderItem(item) {

    const onPress = () => {
      AlertIOS.prompt(
        'Edit or Delete Item',
         null,
        [
      // {text: 'Edit', onPress: (text) =>    

this.itemsRef.child(item._key).update({address: this.state.region})},
      {text: 'Delete', onPress: (text) => 

this.itemsRef.child(item._key).remove()},
      {text: 'Cancel', onPress: (text) => console.log('Cancelled')}
    ]
  );
};


   return (
       <ListItem item={item} onPress={onPress} />
    );
  }

}





AppRegistry.registerComponent('Map_app2', () => Map_app2);

Solution

  • Ok So I found out the answer. To replace the date in the this.state.region area using the _addItem function onPress I needed to set this.state.region to equal the latitude and longitude from the geo coder I was using to convert addresses into coordinates. So I needed to use the following:

    _addItem() {
      AlertIOS.prompt(
        'Look up address',
         null,
        [{text: 'Cancel', onPress: () => console.log('Cancel Pressed'), 
    
                 style:'cancel'},
    
      {
      text: 'Enter',
      onPress: (value) => Geocoder.geocodeAddress(value).then(res => {
                // res is an Array of geocoding object (see below)
    
                        this.state.coordinate.latitude = res[0].position.lat 
                        this.state.coordinate.longitude = res[0].position.lng
             //I needed to set this region equal to the conversion of the address from within the geo coder to the latitude and longitude of the address.
                         this.state.region = {latitude: res[0].position.lat,
                                              longitute: res[0].position.lng}
    
                        this.onRegionChange(this.state.region)
                        this.itemsRef.push({address: res[0].formattedAddress})
    
            })
    
               .catch(err => console.log(err)) 
     }],
     'plain-text'
    

    ); }