How to stop the google map from re rendering and keeping just the values in input fields when marker is placed on different locations?

こ雲淡風輕ζ 提交于 2020-01-24 00:22:40

问题


I did a lot of research on this but i am not getting any solutions so please look through and help me, Basically its like when we select a location on the map by dragging the marker ,i don't want the map to refresh and reset the values and also the pin is coming back to the center after re render takes place,

Is there any solution in "shouldcomponentupdate" ?? which doesn't allow you to re render the whole thing but by keep updating the values which were retrieved like address ,lat and long in input field when i move the marker from one locaton to another!!

And also i tried different things in shouldcomponentupdate method like by returning it as false , but over there map was not re rendering i could drag the pin from where i left off , i could see the locations getting updated in the console below , but values of those locations were not displaying in the input fields provided !

In simple words if i want to say, whenever i drag and drop the pin on location ,location value must be retrieved continuous without the pin coming back to the center of the map, so that i can resume retrieving of location from where i left the marker pin on the map .

Please Help Me out !! I took this code from the net i want to implement those bit of changes

import React, { Component } from 'react';
import { withGoogleMap, GoogleMap, withScriptjs, InfoWindow, Marker } from "react-google-maps";
import Geocode from "react-geocode";
import Autocomplete from 'react-google-autocomplete';
Geocode.setApiKey( "AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0" );
Geocode.enableDebug();

class Map extends Component{

constructor( props ){
    super( props );
    this.state = {
        address: '',
        city: '',
        area: '',
        state: '',
        mapPosition: {
            lat: this.props.center.lat,
            lng: this.props.center.lng
        },
        markerPosition: {
            lat: this.props.center.lat,
            lng: this.props.center.lng
        }
    }
}
/**
 * Get the current address from the default map position and set those values in the state
 */
componentDidMount() {
    Geocode.fromLatLng( this.state.mapPosition.lat , this.state.mapPosition.lng ).then(
        response => {
            const address = response.results[0].formatted_address,
                addressArray =  response.results[0].address_components,
                city = this.getCity( addressArray ),
                area = this.getArea( addressArray ),
                state = this.getState( addressArray );

            console.log( 'city', city, area, state );

            this.setState( {
                address: ( address ) ? address : '',
                area: ( area ) ? area : '',
                city: ( city ) ? city : '',
                state: ( state ) ? state : '',
            } )
        },
        error => {
            console.error( error );
        }
    );
};
/**
 * Component should only update ( meaning re-render ), when the user selects the address, or drags the pin
 *
 * @param nextProps
 * @param nextState
 * @return {boolean}
 */


shouldComponentUpdate( nextProps, nextState ){
        if (
            this.state.markerPosition.lat !== this.props.center.lat ||
            this.state.address !== nextState.address ||
            this.state.city !== nextState.city ||
            this.state.area !== nextState.area ||
            this.state.state !== nextState.state
        ) {
            return true
        } else if ( this.props.center.lat === nextProps.center.lat ){
            return false
        }
    }
/**
 * Get the city and set the city input value to the one selected
 *
 * @param addressArray
 * @return {string}
 */
getCity = ( addressArray ) => {
    let city = '';
    for( let i = 0; i < addressArray.length; i++ ) {
        if ( addressArray[ i ].types[0] && 'administrative_area_level_2' === addressArray[ i ].types[0] ) {
            city = addressArray[ i ].long_name;
            return city;
        }
    }
};
/**
 * Get the area and set the area input value to the one selected
 *
 * @param addressArray
 * @return {string}
 */
getArea = ( addressArray ) => {
    let area = '';
    for( let i = 0; i < addressArray.length; i++ ) {
        if ( addressArray[ i ].types[0]  ) {
            for ( let j = 0; j < addressArray[ i ].types.length; j++ ) {
                if ( 'sublocality_level_1' === addressArray[ i ].types[j] || 'locality' === addressArray[ i ].types[j] ) {
                    area = addressArray[ i ].long_name;
                    return area;
                }
            }
        }
    }``
};
/**
 * Get the address and set the address input value to the one selected
 *
 * @param addressArray
 * @return {string}
 */
getState = ( addressArray ) => {
    let state = '';
    for( let i = 0; i < addressArray.length; i++ ) {
        for( let i = 0; i < addressArray.length; i++ ) {
            if ( addressArray[ i ].types[0] && 'administrative_area_level_1' === addressArray[ i ].types[0] ) {
                state = addressArray[ i ].long_name;
                return state;
            }
        }
    }
};
/**
 * And function for city,state and address input
 * @param event
 */
onChange = ( event ) => {
    this.setState({ [event.target.name]: event.target.value });
};
/**
 * This Event triggers when the marker window is closed
 *
 * @param event
 */
onInfoWindowClose = ( event ) => {

};

/**
 * When the marker is dragged you get the lat and long using the functions available from event object.
 * Use geocode to get the address, city, area and state from the lat and lng positions.
 * And then set those values in the state.
 *
 * @param event
 */
onMarkerDragEnd = ( event ) => {
    let newLat = event.latLng.lat(),
        newLng = event.latLng.lng();

    Geocode.fromLatLng( newLat , newLng ).then(
        response => {
            const address = response.results[0].formatted_address,
                addressArray =  response.results[0].address_components,
                city = this.getCity( addressArray ),
                area = this.getArea( addressArray ),
                state = this.getState( addressArray );
            this.setState( {
                address: ( address ) ? address : '',
                area: ( area ) ? area : '',
                city: ( city ) ? city : '',
                state: ( state ) ? state : ''
            } )
        },
        error => {
            console.error(error);
        }
    );
};

/**
 * When the user types an address in the search box
 * @param place
 */
onPlaceSelected = ( place ) => {
    console.log( 'plc', place );
    const address = place.formatted_address,
        addressArray =  place.address_components,
        city = this.getCity( addressArray ),
        area = this.getArea( addressArray ),
        state = this.getState( addressArray ),
        latValue = place.geometry.location.lat(),
        lngValue = place.geometry.location.lng();
    // Set these values in the state.
    this.setState({
        address: ( address ) ? address : '',
        area: ( area ) ? area : '',
        city: ( city ) ? city : '',
        state: ( state ) ? state : '',
        markerPosition: {
            lat: latValue,
            lng: lngValue
        },
        mapPosition: {
            lat: latValue,
            lng: lngValue
        },
    })
};


render(){
    const AsyncMap = withScriptjs(
        withGoogleMap(
            props => (
                <GoogleMap google={ this.props.google }
                           defaultZoom={ this.props.zoom }
                           defaultCenter={{ lat: this.state.mapPosition.lat, lng: this.state.mapPosition.lng }}
                >
                    {/* InfoWindow on top of marker */}
                    <InfoWindow
                        onClose={this.onInfoWindowClose}
                        position={{ lat: ( this.state.markerPosition.lat + 0.0018 ), lng: this.state.markerPosition.lng }}
                    >
                        <div>
                            <span style={{ padding: 0, margin: 0 }}>{ this.state.address }</span>
                        </div>
                    </InfoWindow>
                    {/*Marker*/}
                    <Marker google={this.props.google}
                            name={'Dolores park'}
                            draggable={true}
                            onDragEnd={ this.onMarkerDragEnd }
                            position={{ lat: this.state.markerPosition.lat, lng: this.state.markerPosition.lng }}
                    />
                    <Marker />
                    {/* For Auto complete Search Box */}
                    <Autocomplete
                        style={{
                            width: '100%',
                            height: '40px',
                            paddingLeft: '16px',
                            marginTop: '2px',
                            marginBottom: '100px'
                        }}
                        onPlaceSelected={ this.onPlaceSelected }
                        types={['(regions)']}
                    />
                </GoogleMap>
            )
        )
    );
    let map;
    if( this.props.center.lat !== undefined ) {
        map = <div>
            <div>
                <div className="form-group">
                    <label htmlFor="">City</label>
                    <input type="text" name="city" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.city }/>
                </div>
                <div className="form-group">
                    <label htmlFor="">Area</label>
                    <input type="text" name="area" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.area }/>
                </div>
                <div className="form-group">
                    <label htmlFor="">State</label>
                    <input type="text" name="state" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.state }/>
                </div>
                <div className="form-group">
                    <label htmlFor="">Address</label>
                    <input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.address }/>
                </div>
            </div>

            <AsyncMap
                googleMapURL="https://maps.googleapis.com/maps/api/js?key=AIzaSyDGe5vjL8wBmilLzoJ0jNIwe9SAuH2xS_0&libraries=places"
                loadingElement={
                    <div style={{ height: `100%` }} />
                }
                containerElement={
                    <div style={{ height: this.props.height }} />
                }
                mapElement={
                    <div style={{ height: `100%` }} />
                }
            />
        </div>
    } else {
        map = <div style={{height: this.props.height}} />
    }
    return( map )
}
}

export default Map

回答1:


I was searching solution for the same issue, when I found your question. I know its late post, but my answer will help those who are getting here. shouldComponentUpdate() method is used to avoid unnecessary renders of the component. So, we have to place conditions in this method so as to return true or false based on that. In your code - replace the shouldcomponentupdate method as follows:

    shouldComponentUpdate( nextProps, nextState ){
    if (
    this.state.markerPosition.lat !== this.props.center.lat ||
    this.state.address !== nextState.address 
    ) {
    return false
    } else if ( this.props.center.lat === nextProps.center.lat ){
    return true
    }
}

That worked for me. Hope that helps. Thank you!



来源:https://stackoverflow.com/questions/54476519/how-to-stop-the-google-map-from-re-rendering-and-keeping-just-the-values-in-inpu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!