getPlace 函数不适用于 Google 自动完成反应

getPlace function not working with Google Autocomplete in react

我正在尝试在 React 中重新创建这个 Google 自动完成示例:https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete-addressform

我正在使用本教程生成正确加载 Google API 所需的高阶组件:https://www.fullstackreact.com/articles/how-to-write-a-google-maps-react-component/

自动完成功能似乎工作正常。但是,当我 select 一个建议并尝试 运行 fillInAddress() 这是我得到的错误消息:

Uncaught TypeError: Cannot read property 'getPlace' of undefined

这是我的代码 /components/GoogleApiComponent.jsx

import React from 'react';
import {GoogleApiWrapper} from 'google-maps-react';
import GoogleAutoComplete from '../components/GoogleAutoComplete';


export class Container extends React.Component {
  render() {
    if (!this.props.loaded) {
      return <div>Loading...</div>
    }
    return (
    <div>
      <GoogleAutoComplete 
      />
    </div>

    )
  }
}

export default GoogleApiWrapper({
  apiKey: 'somekey'
})(Container)

../components/GoogleAutoComplete.jsx

import React from 'react';

export default class GoogleAutoComplete extends React.Component {
  static propTypes = {
    }
  constructor(props) {
    super(props);
    }

    componentDidMount() {
      this.initAutocomplete();
    }

    initAutocomplete() {
      this.autocomplete = new google.maps.places.Autocomplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      this.autocomplete.addListener('place_changed', this.fillInAddress);


    }

    geolocate() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          const geolocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
        });
      }
    }

    fillInAddress() {

      const componentForm = {
        street_number: 'short_name',
        route: 'long_name',
        locality: 'long_name',
        administrative_area_level_1: 'short_name',
        country: 'long_name',
        postal_code: 'short_name'
      };
    // Get the place details from the autocomplete object.
      const place = this.autocomplete.getPlace();
      for (let component in componentForm) {
        this.refs.component.value = '';
        this.refs.component.disabled = false;
      }

    // Get each component of the address from the place details
    // and fill the corresponding field on the form.
    for (let i = 0; i < place.address_components.length; i++) {
      const addressType = place.address_components[i].types[0];
      if (componentForm[addressType]) {
        const val = place.address_components[i][componentForm[addressType]];
        this.refs.addressType.value = val;
      }
    }
  }    

  render() {
    return (
      <div>
        <div>
          <input 
            placeholder="Enter your address"
            onFocus={this.geolocate}
            ref="autoCompletePlaces"
          />
        </div>
        <table ref="address">
          <tbody>
            <tr>
              <td>Street address</td>
              <td>
                <input 
                  ref="street_number"
                  disabled="true"/>
              </td>
              <td>
                <input 
                  ref="route"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>City</td>
              <td>
                <input 
                  ref="locality"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>State</td>
              <td>
                <input 
                  ref="administrative_area_level_1" 
                  disabled="true"/>
                </td>
              <td>Zip code</td>
              <td>
                <input
                  ref="postal_code"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>Country</td>
              <td>
                <input
                  ref="country" 
                  disabled="true"/>
              </td>
            </tr>
          </tbody>
        </table>
      </div>      
    );
  }
}

我在 discord, and this other 的人的帮助下解决了这个问题。根据该答案,关键点是 "Inside the place_changed-callback the keyword this points to the object which has been triggered the event."。我进行了更改并且它起作用了。
这是关键线: this.place = this.autocomplete.getPlace();

为了完整起见,我还重构了表单填写 this.place.address_components.forEach((组件, 索引) => {

 const addressType = this.place.address_components[index].types[0];
      if (componentForm[addressType]) {
        const val = this.place.address_components[index][componentForm[addressType]];
        this.refs[addressType].value = val;
      }
    })

完整代码如下:

import React from 'react';

export default class GoogleAutoComplete extends React.Component {
  static propTypes = {
    }
  constructor(props) {
    super(props);
      this.fillInAddress = this.fillInAddress.bind(this);

    }

    componentDidMount() {
      this.initAutocomplete();
    }


    initAutocomplete() {
      const google = window.google;
      this.autocomplete = new google.maps.places.Autocomplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      this.autocomplete.addListener('place_changed', this.fillInAddress);

    }

    geolocate() {
      if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function(position) {
          const geolocation = {
            lat: position.coords.latitude,
            lng: position.coords.longitude
          };
        });
      }
    }

    fillInAddress() {
      const componentForm = {
        street_number: 'short_name',
        route: 'long_name',
        locality: 'long_name',
        administrative_area_level_1: 'short_name',
        country: 'long_name',
        postal_code: 'short_name'
      };
    // Get the place details from the autocomplete object.
      this.place = this.autocomplete.getPlace();
      /*this.setState({placeResult: this.place.address_components})*/

      for (let component in this.componentForm) {
        this.refs.component.value = '';
        this.refs.component.disabled = false;
      }

    // Get each component of the address from the place details
    // and fill the corresponding field on the form.

    this.place.address_components.forEach((component, index) => {
      const addressType = this.place.address_components[index].types[0];
      if (componentForm[addressType]) {
        const val = this.place.address_components[index][componentForm[addressType]];
        this.refs[addressType].value = val;
      }
    })   
  }    

  render() {
    return (
      <div>
        <div>
          <input 
            placeholder="Enter your address"
            onFocus={this.geolocate}
            ref="autoCompletePlaces"
            className="form-control"
            type="text"
          />
        </div>
        <table ref="address">
          <tbody>
            <tr>
              <td>Street address</td>
              <td>
                <input 
                  ref="street_number"
                  disabled="true"
                  value=''
                  />
              </td>
              <td>
                <input 
                  ref="route"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>City</td>
              <td>
                <input 
                  ref="locality"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>State</td>
              <td>
                <input 
                  ref="administrative_area_level_1" 
                  disabled="true"/>
                </td>
              <td>Zip code</td>
              <td>
                <input
                  ref="postal_code"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>Country</td>
              <td>
                <input
                  ref="country" 
                  disabled="true"/>
              </td>
            </tr>
          </tbody>
        </table>
      </div>      
    );
  }
}