react-geosuggest: Unable to get property 'getPlacePredictions' of undefined or null reference

I am seeing this bug periodically with this component. We are using it in production.

The google maps object must have been loaded up because I see that you throw an error in the componentDidMount function if it is not in the window.

Is it possible that the this keyword points to a reference other than the Geosuggest object?

The bug has occurred in the following browsers:

  • Edge 13
  • Chrome Mobile 34
  • Chrome 49
  • IE 10
  • Chrome Mobile 48

Below is the stack trace:

~/react-geosuggest/module/Geosuggest.js in searchSuggests at line 233:0

        options.componentRestrictions = {
          country: this.props.country
        };
      }
      this.autocompleteService.getPlacePredictions(options, function (suggestsGoogle) {
        _this4.updateSuggests(suggestsGoogle || []); // can be null
        if (_this4.props.autoActivateFirstSuggest) {
          _this4.activateSuggest('next');
        }
~/react-geosuggest/module/Geosuggest.js in showSuggests at line 292:0

     */
  }, {
    key: 'showSuggests',
    value: function showSuggests() {
      this.searchSuggests();
      this.setState({ isSuggestsHidden: false });
    }
    /**
     * Hide the suggestions
~/react-geosuggest/module/Geosuggest.js in apply at line 152:0

  }, {
    key: 'onInputFocus',
    value: function onInputFocus() {
      this.props.onFocus();
      this.showSuggests();
    }
    /**
     * When the input gets blurred
     */

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 16 (8 by maintainers)

Most upvoted comments

I ran into this error today, and what fixed it for me was making sure <Geosuggest /> only rendered after the Google Maps API was instantiated. I’m attaching a <script> tag to the page with a 'load' event listener, then returning a promise that I then use to render the component. Hope this helps someone.

@joevo2 here’s a quick and dirty example based on some old code I wrote to solve this:

/* utils/window.js */
export function loadScriptAsync(src) {
  const script = window.document.createElement('script')
  script.src = src
  script.async = true
  script.defer = true

  const promise = new Promise((resolve, reject) => {
    script.addEventListener('load', (event) => {
      resolve(event)
    }, false)

    script.addEventListener('error', (error) => reject(error))
  })

  window.document.body.appendChild(script)
  return promise
}
/* lib/google.js */
import { loadScriptAsync } from 'utils/window'

const googleAPIKeys = {
  development: GOOGLE_MAPS_DEV_KEY,
  staging:     GOOGLE_MAPS_STAGING_KEY,
  production:  GOOGLE_MAPS_PROD_KEY,
}

const getGoogleMapsAPIUrl = key => `https://maps.googleapis.com/maps/api/js?key=${key}&libraries=places`
export const initGoogleMapsAPI = () => loadScriptAsync(getGoogleMapsAPIUrl(googleAPIKeys[env]))
/* components/Map/Map.jsx */
import GoogleMap from 'google-map-react'
import Icon from 'components/Icon/Icon'
import { initGoogleMapsAPI } from 'lib/google'

export default class Map extends React.Component {

  state = {
    gMapsLoaded: false,
  }

  componentDidMount = () => {
    if (!window.google) {
      initGoogleMapsAPI().then(() => {
        this.setState({ gMapsLoaded: true })
      })
    }
  }

  render = () => {
    if (!this.state.gMapsLoaded) {
      return null
    }

    const { lat, lng } = this.props.address
    const coordinates = {
      lat: parseFloat(lat),
      lng: parseFloat(lng),
    }

    return (
      <GoogleMap center={coordinates} zoom={14}>
        <Icon name="location-pin" {...coordinates} />
      </GoogleMap>
    )
  }
}

Edit: It’s been a while since I last used this library—I just realized that this issue is for Geosuggest, and not google-map-react, but the idea is still the same.

For this, I created an <AddressInput /> component that wrapped <Geosuggest />, and rendered a standard input (styled the same) if window.google wasn’t available, then rendered the <Geosuggest /> component after it loaded.