如何在 React 中加载 Google 地方 API

How to load the Google Places API in React

我想在我的 React 应用程序中使用 Google 地图和地点 API,以便用户能够在地图上找到他们所在地区的医院。

我正在使用@react-google-maps/api 和use-places-autocomplete npm 包来与API 交互以显示地图和地点。我正在使用 useLoadScript 挂钩加载我的 API 密钥并声明我将使用的库。

在这种情况下,正如我启用地点和地图 JavaScript API 一样,我在库数组中提供了 地点

我尝试将以下脚本添加到 index.html 文件中:

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places"></script>

但我收到错误消息:您正在多次加载地图。

这是我的代码片段,其中我使用了来自 @react-google-maps/api 的 useLoadScript 挂钩

请问我该如何解决这个问题?

如果您使用的是 @react-google-maps/api libraryuse-places-autocompleteuseLoadScript,您需要提供 ['places'] 作为您的图书馆的价值才能使用地点自动完成功能在你的代码中。请注意,此 useLoadScript 将在您的代码中加载 Google 地图 JavaScript 脚本标签,您不再需要在 html 文件中添加脚本标签。

据我了解,在您的用例中,用户将 select 从自动完成下拉列表中选择一个地点,并且应在地图中返回最近的医院。

为此,您需要具备以下流程:

  1. 在搜索地点时使用use-places-autocomplete提供地点建议。该库有一个 GetGeocode 和一个 GetLatLng,您可以使用它们来获取所选地点的坐标。
  2. 获得坐标后,您可以使用 Places API Nearby Search,在请求中使用关键字 hospital 并定义半径。这将以所选地点为中心搜索定义半径内的医院列表。
  3. 您可以遍历结果列表并将每个坐标固定为地图中的标记。

这是 sample code 和下面的代码片段。确保添加您的 API 密钥:

Index.js

import React from "react";
import { render } from "react-dom";
import Map from "./Map";

render(<Map />, document.getElementById("root"));

Map.js

/*global google*/
import React from "react";
import { GoogleMap, useLoadScript } from "@react-google-maps/api";
import Search from "./Search";

let service;
const libraries = ["places"];

const mapContainerStyle = {
  height: "100vh",
  width: "100vw"
};
const options = {
  disableDefaultUI: true,
  zoomControl: true
};
const center = {
  lat: 43.6532,
  lng: -79.3832
};

export default function App() {
  const { isLoaded, loadError } = useLoadScript({
    googleMapsApiKey: "YOUR_API_KEY",
    libraries
  });
  const mapRef = React.useRef();
  const onMapLoad = React.useCallback(map => {
    mapRef.current = map;
  }, []);

  const panTo = React.useCallback(({ lat, lng }) => {
    mapRef.current.panTo({ lat, lng });
    mapRef.current.setZoom(12);
    let map = mapRef.current;

    let request = {
      location: { lat, lng },
      radius: "500",
      type: ["hospital"]
    };

    service = new google.maps.places.PlacesService(mapRef.current);
    service.nearbySearch(request, callback);
    function callback(results, status) {
      if (status === google.maps.places.PlacesServiceStatus.OK) {
        for (let i = 0; i < results.length; i++) {
          let place = results[i];
          new google.maps.Marker({
            position: place.geometry.location,
            map
          });
        }
      }
    }
  }, []);

  return (
    <div>
      <Search panTo={panTo} />
      <GoogleMap
        id="map"
        mapContainerStyle={mapContainerStyle}
        zoom={8}
        center={center}
        options={options}
        onLoad={onMapLoad}
      />
    </div>
  );
}

Search.js

import React from "react";
import usePlacesAutocomplete, {
  getGeocode,
  getLatLng
} from "use-places-autocomplete";

export default function Search({ panTo }) {
  const {
    ready,
    value,
    suggestions: { status, data },
    setValue,
    clearSuggestions
  } = usePlacesAutocomplete({
    requestOptions: {
      /* Define search scope here */
    },
    debounce: 300
  });

  const handleInput = e => {
    // Update the keyword of the input element
    setValue(e.target.value);
  };

  const handleSelect = ({ description }) => () => {
    // When user selects a place, we can replace the keyword without request data from API
    // by setting the second parameter to "false"
    setValue(description, false);
    clearSuggestions();

    // Get latitude and longitude via utility functions
    getGeocode({ address: description })
      .then(results => getLatLng(results[0]))
      .then(({ lat, lng }) => {
        panTo({ lat, lng });
      })
      .catch(error => {
        console.log(" Error: ", error);
      });
  };

  const renderSuggestions = () =>
    data.map(suggestion => {
      const {
        place_id,
        structured_formatting: { main_text, secondary_text }
      } = suggestion;

      return (
        <li key={place_id} onClick={handleSelect(suggestion)}>
          <strong>{main_text}</strong> <small>{secondary_text}</small>
        </li>
      );
    });

  return (
    <div>
      <input
        value={value}
        onChange={handleInput}
        disabled={!ready}
        placeholder="Where are you going?"
      />
      {/* We can use the "status" to decide whether we should display the dropdown or not */}
      {status === "OK" && <ul>{renderSuggestions()}</ul>}
    </div>
  );
}