zulqarnain
zulqarnain

Reputation: 1626

unable to stop rendering component in Reactjs

in my reactjs app, I'm using Redux, Redux-Thunk.In my component using google-maps, I want to implement center_changed using Markers.so whenever i move the marker latlng and address also will change. when im saving state component getting refresh.so i want to stop rendering my component using shouldComponentUpdate. but when i was returning false from shouldComponentUpdate then also map getting refresh.
my component

class StepTwo extends React.Component{
    constructor(props){
        super(props);
        this.state={
            pickupConfirmButton:false,
            dropoffConfirmButton:false,
        }
        this.mapLoaded = false;
        this.map=false;
        this.pickMarker=false;
        this.pickIcon = '';
        this.dropMarker=false;
        this.dropIcon='';
    }
    componentWillReceiveProps(props){
        if (props.isScriptLoadSucceed) {
            this.mapLoaded= true;
            this.directionsService = new google.maps.DirectionsService();
            this.directionsDisplay = new google.maps.DirectionsRenderer({ suppressMarkers: true });

            this.map = new google.maps.Map(document.getElementById('map'), {
                zoom: 14,
                center: { lat: 17.3850, lng: 78.4867 },
                mapTypeControl: false,
                streetViewControl: false,
                gestureHandling:'greedy',
            });

            this.pickMarker = new google.maps.Marker   ({
                icon:this.pickIcon,
                map: this.map,
                animation: google.maps.Animation.DROP,
                position: { lat: 17.3850, lng: 78.4867 },
                // draggable: true
            });
            this.dropIcon = {
                path: 'M 0,0 C -2,-20 -10,-22 -10,-30 A 10,10 0 1,1 10,-30 C 10,-22 2,-20 0,0 z M -2,-30 a 2,2 0 1,1 4,0 2,2 0 1,1 -4,0',
                fillColor: '#00E64D',
                fillOpacity: 1,
                strokeColor: '#000',
                strokeWeight: 1,
                scale: 1,
            };

            this.pickMarker.addListener('click', () =>{
                this.pickupMarkerClickListener();
            });
        }
    }
    shouldComponentUpdate(nextProps, nextState) {
        if (this.props.pickupAddress || nextProps.pickupAddress) {
           //after return false also i'm unable to stop rendering 
           //component
            return false;
        }
    }

    pickupMarkerClickListener = () =>{
        if(this.dropMarker){
            this.dropMarker.setVisible(false);
        }
        this.directionsDisplay.set('directions', null);
        this.map.setCenter(this.pickMarker.getPosition());
        this.map.setZoom(18);

        this.map.addListener('center_changed',  () => {
            let lat=this.map.getCenter().lat();
            let lng=this.map.getCenter().lng();
            let pickLatlng ={lat:lat,lng:lng};
            //on below function when i want to send latlng to redux state component getting refresh.
            // this.props.pickupHandler(pickLatlng);
            let geocoder = new google.maps.Geocoder;
                geocoder.geocode({'location': {lat:lat,lng:lng}}, (results, status) =>{
                    if (status === 'OK') {
                        ////////////////////////////////////////////////////////
                        //////// this is function which getting refresh/////////
                        ///////////////////////////////////////////////////////
                        this.props.pickupAddHandler(results[0].formatted_address);
                    }
                })
            this.pickMarker.setPosition({lat:lat,lng:lng});
        })
    }
    render(){
        return(
            <Row type="flex" justify="space-around" align="middle" className='stepTwo'>
                <Col lg={{span:10}} className="form" >
                    <Input 
                            className='input'
                            placeholder='Enter Pick-up Locaiton'
                            id='pick'
                            ref="pickupInput"
                            onChange={this.pickupSearch}
                            // value={this.props.pickupAddress}
                        />
                    <div style={{padding:'1rem'}} align='center'>
                    <Button><Icon type="swap"  className="swapIcon" /> </Button><span style={{fontSize:'0.8rem'}}>*Reverse Location</span>
                    </div>
                    <Input 
                        className='input'
                        placeholder='Enter Drop-off Locaiton'
                        ref="dropoffInput"
                        onChange={this.dropoffSearch}

                    />
                </Col>
                <Col lg={{span:13}}>
                    <div id="map"  className='map'></div>
                    {this.state.pickupConfirmButton && <Button  className="cnfrmBtn"  size="large" onClick={this.pickupMaker}>Confirm Location</Button> }
                    {this.state.dropoffConfirmButton && <Button className="cnfrmBtn" size="large" onClick={this.dropoffMaker}>Confirm Location</Button> }
                </Col>
            </Row>
        )
    }
}

const StepTwoLoadedMap = scriptLoader(
    [config.MapApi]
)(StepTwo);

const mapStateToProps = (state) =>{
    console.log(state.StepTwoReducer.pickupLatlng,'mapState')
    return{
        pickupAddress:state.StepTwoReducer.pickupAddress,
        pickupLocation:state.StepTwoReducer.pickupLatlng
    }
}
export default connect(mapStateToProps,{validationS2,pickupAddHandler,pickupHandler,dropoffHandler})(StepTwoLoadedMap);

ActionCreator

export function pickupAddHandler(address){
    return function(dispatch){
        dispatch({type:PICKUPADD,payload:address})
    }
}

export function pickupHandler(latlng) {

    return function(dispatch) {
        dispatch({ type: PICKUP_LATLNG,payload:latlng });
    };
}

Reducer.js

import {VALIDS2,PICKUPADD,PICKUP_LATLNG} from '../actions/types';
const INITIAL_STATE = {
    validStepTwo:false,
    pickupAddress:null,
    pickupLatlng:false,
};
export default  (state=INITIAL_STATE,action) => {
    // console.log(action,'step two')
    switch(action.type) {
        case PICKUPADD: 
            return {...state,pickupAddress:action.payload}
        case PICKUP_LATLNG:
            return {...state,pickupLatlng:action.payload}
        case VALIDS2:
            return {...state,validStepTwo:action.payload};
        default:
            return state;
    }
}

how can I store address and latlng on redux state when center_changed, without rendering component.
another problem is when i change center of the map i will get address, that address I'm storing pickupAddress state if we stop rendering component, there is input field so I want to show that address as input field value, if component not re-render then how can i show current address inside input field.
some reasons i don't want to use any library
anyone can please help me how can store redux state without rendering but it should show the updated value inside input fields or any other simple method,i'm stuck since 1 week!plzzzzzz

Upvotes: 0

Views: 609

Answers (1)

tarzen chugh
tarzen chugh

Reputation: 11257

Always try to create a container component for third party libraries(google map in this case) and Always return false in shouldComponentUpdate lifecycle method. Sample code to give context of its use.

// GoogleMapComponent.jsx
import React, { Component } from 'react'

export default class GoogleMap extends Component {
    shouldComponentUpdate() {
        return false;
    }
    componentDidMount() {
        this.map = new google.maps.Map( this.refs.map, {
            center: {lat: this.props.lat, lng: this.props.lng},
            zoom: 5
        })
    }
    componentWillReceiveProps(nextProps) {
        this.map.panTo({ lat: nextPros.lat, lng: nextPros.lng });
    }
    render() {
        return (
            <div id="googleMap" ref="map" />
        )
    }
}


// App.jsx
import GoogleMap from './GoogleMapComponent'
import React, { Component } from 'react'

export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {lat: 30.397, lng: 130.876};
    }
    render() {
        return (
            <div style={{ height: '100%'}} >
                <button onClick={() => this.seState({ lat:50.712, lng: -30.08 }) }>
                    Your Favourite Place
                </button>
                <GoogleMap
                    lat={this.state.lat}
                    lng={this.state.lng}
                />
            </div>
        )
    }
}

This may not be the perfect answer to your problem, but will surely improve the structure of code and help resolve the issue. Hope that helps!!

Upvotes: 1

Related Questions