Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop map from re-rendering every time state changes #220

Closed
figalex opened this issue Feb 28, 2016 · 11 comments
Closed

Stop map from re-rendering every time state changes #220

figalex opened this issue Feb 28, 2016 · 11 comments

Comments

@figalex
Copy link

figalex commented Feb 28, 2016

Maybe I'm doing something else wrong, but right now every time my application state gets changed the map component goes gray and re-draws the same map with the same marker. On my use case I actually don't need any interaction with the map, I just want to display the marker and I know it will not change in the future, so I was wondering, is there a way to have like a read-only mode for the map? I want just to render the map one time and to for the map to stay like that even if the there are some state changes.

@figalex figalex changed the title Stop map from re-rendering every time state change Stop map from re-rendering every time state changes Feb 28, 2016
@wedneyyuri
Copy link

You can use a wrapper component and implement the method shouldComponentUpdate:

shouldComponentUpdate: function(nextProps, nextState) {
  // If shouldComponentUpdate returns false, 
  // then render() will be completely skipped until the next state change.
  // In addition, componentWillUpdate and componentDidUpdate will not be called. 
  return false;
}

@figalex
Copy link
Author

figalex commented Mar 15, 2016

Thanks, that was helpful.

@figalex figalex closed this as completed Mar 15, 2016
@tomchentw
Copy link
Owner

tomchentw commented May 29, 2016

Glad it's resolved! We're also looking for maintainers. Involve in #266 to help strengthen our community!

@foloinfo
Copy link

In case if anyone faced same issue and struggled like me, here is a sample component based on comment above.

<Map
  center={{lat: 35.6688654, lng: 139.4611935}}
  height='300px'
  zoom={15}
/>
import React from 'react'
import { withGoogleMap, GoogleMap } from "react-google-maps"
import withScriptjs from "react-google-maps/lib/async/withScriptjs"

class Map extends React.Component{

  constructor(props){
    super(props)
  }

  shouldComponentUpdate(nextProps, nextState){
    if(this.props.center.lat === nextProps.center.lat){
      return false
    }else{
      return true
    }
  }

  render(){
    const AsyncMap = withScriptjs(
      withGoogleMap(
        props => (
          <GoogleMap
            defaultZoom={this.props.zoom}
            defaultCenter={{ lat: this.props.center.lat, lng: this.props.center.lng }}
          >
          </GoogleMap>
        )
      )
    )
    var map
    if(this.props.center.lat !== undefined){
      map = <AsyncMap
        googleMapURL="https://maps.googleapis.com/maps/api/js?key=your_key"
        loadingElement={
          <div style={{ height: `100%` }} />
        }
        containerElement={
          <div style={{ height: this.props.height }} />
        }
        mapElement={
          <div style={{ height: `100%` }} />
        }
      />
    }else{
      map = <div style={{height: this.props.height}} />
    }
    return(map)
  }
}

export default Map

it avoids InvalidValueError: setPosition: not a LatLng or LatLngLiteral: in property lat: not a number error, and flicker re-rendering of map.

@NickBrooks
Copy link

I am having the exact same issue, except I don't want a read only map and I need to load the updated props...

gmapsreload

My code is here, props.map.markers holds the markers array so shouldComponentUpdate needs to return true when the markers have been updated...

shouldComponentUpdate(nextProps, nextState) {
        if (this.props.profile != nextProps.profile) {
            return true;
        }

        if (this.props.map != nextProps.map) {
            return true;
        }

        if (this.state == nextState) {
            return false;
        }

        return true;
    }

@NickBrooks
Copy link

NickBrooks commented Aug 1, 2017

Okay - I found the problem, the withGoogleMap component must be outside the component you used to render it, like this:

import React from 'react';
import { withGoogleMap, GoogleMap, Marker } from "react-google-maps";

const RenderMap = withGoogleMap(props => (
    <GoogleMap
        ref={props.onMapLoad}
        onClick={props.onMapClick}
        defaultZoom={13}
        center={props.center}>
        {
            props.markers.map(marker => (
                <Marker
                    {...marker}
                />
            ))
        }
    </GoogleMap >
));

class Map extends React.Component {
    constructor(props) {
        super(props);
    }

    handleMapLoad(map) {
        this._map = map;
    }

    handleMapClick(event) {
        console.log(event);
    }

    render() {
        return (
            <div>
                <RenderMap
                    onMapLoad={this.handleMapLoad}
                    onMapClick={this.handleMapClick}
                    {...etc}
                />
            </div>
        )
    }
}

export default Map;

NickBellamy added a commit to NickBellamy/UK-Police-Station-Finder that referenced this issue Aug 8, 2018
Previously, the map reloaded everytime a new area or a new neighbouthood
was selected.  This was unnecessary as only the markers should be re-
rendered.  Seperating out the map wrapper (RenderMap) from the Map
component fixed this issue.

tomchentw/react-google-maps#220 (comment)
@dwatts3624
Copy link

@NickBrooks I was just about to pull the plug on this component but I knew I must be doing something wrong since it's so popular. I never would have guessed to pull the definition out of the component! Thank you!

Scruffy21 added a commit to Scruffy21/ND-Castles-React-Map that referenced this issue Aug 23, 2018
@kulkarnipradnyas
Copy link

my map is flickering on outside change.I have a scenario where marker will change dynamically on outer change(prop).Each time my data changes my map starts dancing.Please help me out with the solution or any concept which will help me.

@MadCoderr
Copy link

my map is flickering on outside change.I have a scenario where marker will change dynamically on outer change(prop).Each time my data changes my map starts dancing.Please help me out with the solution or any concept which will help me.

If anyone struggling with the above mention problem, the way I tackle is to check a single state in shouldComponentUpdate() function.

every time I need to re-render the map I would update the state and let shouldComponentUpdate() return true to re-render the map.

const [refCount, setRefCount] = useState(0);

  getDirection(coords, _eCoords)
      .then((result) => {
        if (result.status === "OK") {
          setDirection(result);
          setRefCount((count) => count + 1); // update state
        } else {
          console.error(`error fetching directions ${result}`);
        }
      })
  shouldComponentUpdate(nextProps) {
    if (nextProps.refCount !== this.props.refCount) return true;

    return false;
  }

@mariraja-selvakumar
Copy link

I have used package '@react-google-maps/api' & separate components for map & markers. The data for both components from redux state. I have to call API in every 5 seconds and the data have to dispatch to redux store. An update occurs in redux state causes the map & marker re-render. Then, How I fix that ?

@muhammadqazi
Copy link

Okay - I found the problem, the withGoogleMap component must be outside the component you used to render it, like this:

import React from 'react';
import { withGoogleMap, GoogleMap, Marker } from "react-google-maps";

const RenderMap = withGoogleMap(props => (
    <GoogleMap
        ref={props.onMapLoad}
        onClick={props.onMapClick}
        defaultZoom={13}
        center={props.center}>
        {
            props.markers.map(marker => (
                <Marker
                    {...marker}
                />
            ))
        }
    </GoogleMap >
));

class Map extends React.Component {
    constructor(props) {
        super(props);
    }

    handleMapLoad(map) {
        this._map = map;
    }

    handleMapClick(event) {
        console.log(event);
    }

    render() {
        return (
            <div>
                <RenderMap
                    onMapLoad={this.handleMapLoad}
                    onMapClick={this.handleMapClick}
                    {...etc}
                />
            </div>
        )
    }
}

export default Map;

nice one !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants