Search code examples
react-nativegoogle-mapsreact-native-maps

React native maps MapView Region not updating on MarkerDrag


I am trying to implement to search and pinpoint a location in react native. I am using react-native-maps and react-native-google-places-autocomplete packages for their obvious usages.
First I have initiated region in the state as:

   constructor(){
    this.state={
         mapRegion: {
                        latitude: this.props.latitude ? this.props.latitude : 27.7172,
                        longitude: this.props.longitude ? this.props.longitude : 85.3240,
                        latitudeDelta: 0.005,
                        longitudeDelta: 0.005,
                    },
    }
    }

I have tried to update the region on pressing the autocompleted search results as well as upon marker drag. But I get an error as:

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

I have implemented the code as:

               <GooglePlacesAutocomplete
                            placeholder='Search'
                            fetchDetails={true}
                            onPress={(data, details = null) => {
                                let tempMapRegion = this.state.mapRegion;
                                tempMapRegion.latitude = details.geometry.location.lat;
                                tempMapRegion.longitude = details.geometry.location.lng;
                                this.setState({ mapRegion: tempMapRegion })
                            }}
                            query={{
                                key: AppSettings.googleMapApiKey,
                                language: 'en',
                            }}
                        />
                        <MapView
                            initialRegion={{
                                latitude: this.props.latitude ? this.props.latitude : 27.7172,
                                longitude: this.props.longitude ? this.props.longitude : 85.3240,
                                latitudeDelta: 0.005,
                                longitudeDelta: 0.005,
                            }}
                            region={this.state.mapRegion}
                            onRegionChange={(e) => { this.onRegionChange(e) }}
                            style={{ height: 300, width: 300 }}
                        >
                            <Marker draggable
                                coordinate={this.state.mapRegion}
                                onDragEnd={(e) => {
                                    let tempMapRegion = this.state.mapRegion;
                                    tempMapRegion.latitude = e.nativeEvent.coordinate.latitude
                                    tempMapRegion.longitude = e.nativeEvent.coordinate.longitude
                                    this.setState({ mapRegion: tempMapRegion })
                                }}
                            />
                        </MapView>

The onRegionChange in the MapView works smoothly and marker is dragged automatically to the centre, but the reverse process brings up the above error.

What is causing this error and how do I get past this?


Solution

  • <View style={{ padding: 2, }}>
                                <GooglePlacesAutocomplete
                                    placeholder='Search'
                                    fetchDetails={true}
                                    onPress={(data, details = null) => {
                                        let tempMapRegion = this.state.mapRegion;
                                        tempMapRegion.latitude = details.geometry.location.lat;
                                        tempMapRegion.longitude = details.geometry.location.lng;
                                        this.map.animateToRegion(this.newRegion(tempMapRegion));
                                        this.setState({ address: data.description })
    
                                    }}
                                    query={{
                                        key: AppSettings.googleMapApiKey,
                                        language: 'en',
                                    }}
                                />
                            </View>
                            <MapView
                                provider={this.props.provider}
                                ref={ref => { this.map = ref; }}
                                mapType={MAP_TYPES.TERRAIN}
                                initialRegion={this.state.mapRegion}
                                onRegionChangeComplete={(e) => { this.onRegionChange(e) }}
                                style={{ height: width, width: width, marginTop: -5 }}
                            >
                                <Marker draggable
                                    coordinate={this.state.mapRegion}
                                    onDragEnd={(e) => {
                                        let tempMapRegion = this.state.mapRegion;
                                        tempMapRegion.latitude = e.nativeEvent.coordinate.latitude
                                        tempMapRegion.longitude = e.nativeEvent.coordinate.longitude
                                        this.map.animateToRegion(this.newRegion(tempMapRegion));
                                        // this.setState({ mapRegion: tempMapRegion })
                                    }}
                                />
                            </MapView>
    

    So, what basically did the thing, was using the animateToRegion property of the mapview. It basically animates the view to the mentioned region and then calls the onRegionChange. I had stumbled upon this answer a number if times but it hadnt worked. Weirdly this only works in the build version and not while debugging, not on the emulator at least.

    Thanks to https://stackoverflow.com/a/53836679/5379191 this answer for showing the way though.

       newRegion(tempMapRegion) {
            return {
                ...this.state.mapRegion,
                ...this.regionCoordinate(tempMapRegion),
            };
        }
    
        regionCoordinate(tempMapRegion) {
            return {
                latitude: tempMapRegion.latitude,
                longitude: tempMapRegion.longitude,
            };
        }