谷歌地点自动完成React组件

3
我正在学习React并尝试在Rails应用程序中使用react_on_rails gem创建Google地点自动完成组件。这是我目前的进展,需要一些帮助来完成它。
我认为我遇到了一个问题,无法正确加载Google JavaScript库。请参见下面控制台中的错误消息(注意我在我的应用程序中正确运行了[KEY])。
Navigated to https://react-on-rails-basic-tutorial-mcl282.c9users.io/
js?key=[KEY]&libraries=places&callback=initAutocomplete:102 Uncaught Yc {message: "initAutocomplete is not a function", name: "InvalidValueError", stack: "Error↵    at new Yc (https://maps.googleapis.com/m…libraries=places&callback=initAutocomplete:139:73"}
Yg @ js?key=[KEY]&libraries=places&callback=initAutocomplete:102
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutocomplete:139
google.maps.Load @ js?key=[KEY]&libraries=places&callback=initAutocomplete:21
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutocomplete:138
(anonymous) @ js?key=[KEY]&libraries=places&callback=initAutocomplete:139
createReactElement.js?74ab:40 RENDERED GoogleAutoComplete to dom node with id: GoogleAutoComplete-react-component-f9a3e037-df00-4f35-9a7c-103c33b1208e with props, railsContext: Object {text: "google autocomplete"} Object {inMailer: false, i18nLocale: "en", i18nDefaultLocale: "en", href: "https://react-on-rails-basic-tutorial-mcl282.c9users.io/", location: "/"…}
clientStartup.js?0ac5:149 Uncaught TypeError: ReactOnRails encountered an error while rendering component: GoogleAutoComplete.Original message: Cannot read property 'Autocomplete' of undefined
    at GoogleAutoComplete.initAutocomplete (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:44:48)
    at GoogleAutoComplete.componentDidMount (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3586), <anonymous>:38:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:265:25)
    at measureLifeCyclePerf (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:75:12)
    at eval (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2842), <anonymous>:264:11)
    at CallbackQueue.notifyAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2296), <anonymous>:76:22)
    at ReactReconcileTransaction.close (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3004), <anonymous>:80:26)
    at ReactReconcileTransaction.closeAll (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:206:25)
    at ReactReconcileTransaction.perform (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:2398), <anonymous>:153:16)
    at batchedMountComponentIntoNode (eval at <anonymous> (webpack-bundle.self-cdcd22e….js?body=1:3130), <anonymous>:126:15)

以下是相关代码:

index.html.erb

<html>
  <body>
  <%= react_component("GoogleAutoComplete") %>

  <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAnhYQqHo2V5AcFpcKKPX6rz0bVrw7xmZg&libraries=places&callback=initAutocomplete"
        ></script>
  </body>
</html>

GoogleAutoComplete.jsx

import React, { PropTypes } from 'react';

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

      super(props);
        this.state = { 
          autocomplete: {} 
        }
    }

    componentDidMount() {
      this.initAutocomplete();
    }

    initAutocomplete() {
      // eslint-disable-next-line no-undef
      const autocomplete = new google.maps.places.Autocomplete((this.refs.autoCompletePlaces), {types: ['geocode']});

      autocomplete.addListener('place_changed', this.fillInAddress);
      this.setState({ autocomplete });
    }

    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 = 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 id="locationField">
          <input 
            id="autocomplete" 
            placeholder="Enter your address"
            onFocus={this.geolocate}
            onChange={this.handleInputChange}
            ref="autoCompletePlaces"
          />
        </div>
        <table id="address">
          <tbody>
            <tr>
              <td>Street address</td>
              <td>
                <input 
                  id="street_number"
                  disabled="true"/>
              </td>
              <td>
                <input 
                  id="route"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>City</td>
              <td>
                <input 
                  id="locality"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>State</td>
              <td>
                <input 
                  id="administrative_area_level_1" 
                  disabled="true"/>
                </td>
              <td>Zip code</td>
              <td>
                <input
                  id="postal_code"
                  disabled="true"/>
              </td>
            </tr>
            <tr>
              <td>Country</td>
              <td>
                <input
                  id="country" 
                  disabled="true"/>
              </td>
            </tr>
          </tbody>
        </table>
      </div>      
    );
  }
}

嗨,Michael,我知道这是一篇旧帖子,但在你的问题中有一个HTML脚本中的API密钥 - 可能值得编辑和删除它 :).如果您想将其用作React Hook,我有一篇文章可以帮助您创建/使用Google Places自动完成服务的钩子,请参见此处:https://atomizedobjects.com/blog/react/how-to-use-google-autocomplete-with-react-hooks/ - Atomicts
1个回答

2
该错误发生是因为initComplete()不可用于全局范围内。 initComplete()是一个React组件方法,您不能在组件外调用它。
要将callback参数传递给Google Maps API,您需要异步加载库,而不使用像您所做的<script>标签。
请查看以下存储库以查看如何处理Google Maps库的异步加载。 https://github.com/fullstackreact/google-maps-react

我觉得我在这里理解了概念,需要用包含Google Maps API脚本的高阶组件来加载,为我创建的组件提供所需的功能。然而,我真的不知道如何实施它。他们给出了这个代码示例:'import {GoogleApiWrapper} from 'GoogleMapsReactComponent'// ...export class Container extends React.Component {}export default GoogleApiWrapper({ apiKey: GAPI_KEY })(Container)' 那么我如何将其与我的GoogleAutoComplete.jsx组件一起实现呢? - Michael Lee
@MichaelLee GoogleApiWrapper 组件将 loaded 属性传递给包装的组件。只有在库加载完成后,该属性才会设置为 true。当 prop 改变时,包装的组件将重新渲染自身,并且您可以在 componentDidMount() 中检查 loaded 是否为 true,如果是,则调用 initAutocomplete() - Ming Soon
这个可以工作!唯一让我困扰的是博客有一个错误,请查看此链接:https://github.com/fullstackreact/google-maps-react/issues/18; - Michael Lee
我也想做这件事并理解其概念,但不知道如何实现 - https://stackoverflow.com/questions/46780770/utilizing-google-maps-in-other-components-through-withscriptjs-withgooglemap - 你有什么建议吗?看起来你链接的库有一个特定的辅助程序,由于存储库已经有一段时间没有活动了,所以我宁愿不包含它。 - James L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接