首頁  >  文章  >  web前端  >  使用 Google Maps API 和 React 建立智慧型地址搜尋

使用 Google Maps API 和 React 建立智慧型地址搜尋

Patricia Arquette
Patricia Arquette原創
2024-10-07 22:17:02729瀏覽

Google 提供對其 Maps API 的強大訪問,可用於各種基於位置的功能和地圖相關任務。在本文中,我將解釋我們如何利用 Google AutocompleteService API 建立智慧地址搜尋欄位來取代完整地址表單。

透過使用這種方法,我們簡化了位址輸入過程,使其更快、更準確,從而減少了使用者輸入錯誤並改善了使用者體驗(1 次智慧輸入vs 3 次,呵呵)。

Creating a Smart Address Search with Google Maps API and React

第 1 步:React 中的 Google Maps API 設定

首先,要使用 Maps API,您需要在 Google Maps Platform 中啟用它並取得 API 金鑰。

在我們的專案中,我們使用 @react-google-maps/api 套件(npm i @react-google-maps/api)。

讓我們使用自訂 useGoogleMapsApi 掛鉤初始化 SDK,以使其可在應用程式中重複使用:


const useGoogleMapsApi = () => {
  const api = useJsApiLoader({
    id: "app",
    googleMapsApiKey: "", // set your Public key
  });

  return {
    ...api,
  };
};


第 2 步:使用 Google 自動完成功能進行搜尋

地點自動完成服務提供了一個 API 來在地點內進行搜尋。它提供了2種方法:

  • getQueryPredictions() 傳回的結果不一定有「place_id」。它還可能包括搜尋字詞或餐廳等地點組。
  • getPlacePredictions() 傳回精確的地點和行政實體。

為了實現我們的搜索,我們使用了 getPlacePredictions() 方法。讓我們將此方法添加到我們的程式碼中並從鉤子中返回它。


// Function to search for places using Google Autocomplete Service
const searchPlaces = async (
  query: string,
  options?: Omit<google.maps.places.AutocompletionRequest, "input">
): Promise<Array<google.maps.places.AutocompletePrediction>> => {
  // Load AutocompleteService from Google Maps API
  const { AutocompleteService } = (await google.maps.importLibrary(
    "places"
  )) as google.maps.PlacesLibrary;
  const autocomplete = new AutocompleteService();

  try {
    // Fetch place predictions based on user query
    const { predictions } = await autocomplete.getPlacePredictions({
      ...options, // Optional additional parameters for more precise searches
      input: query, // User's search query (e.g., "Baker Street")
    });

    // Return the list of predictions to display to the user
    return predictions;
  } catch {
    // If there's an error, return an empty array
    return [];
  }
};


AutocompletionRequest 介面使用輸入欄位作為搜尋查詢和其他選項,這使得搜尋更加準確。我們稍後再討論它們。
我們將在演示中使用簡單的輸入和結果清單。


import useGoogleMapsApi from "./useGoogleMapsApi";
import { useEffect, useState } from "react";

export default function App() {
  const { searchPlaces } = useGoogleMapsApi();
  // State to store input value from the user
  const [inputValue, setInputValue] = useState<string>("");

  // State to store the list of place predictions from Google Autocomplete
  const [places, setPlaces] = useState<
    Array<google.maps.places.AutocompletePrediction>
  >([]);

  // Function to handle the search process when the user types a query
  const handleSearch = async (searchQuery: string) => {
    const result = await searchPlaces(searchQuery);
    setPlaces(result);
  };

  // Trigger the search whenever the input value changes
  useEffect(() => {
    handleSearch(inputValue);
  }, [inputValue]);

  return (
    <div style={{ maxWidth: "80%", width: "100%",fontFamily: "sans-serif",}}>
      <input
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
        placeholder="Find an address"
      />
      {places.map((place) => (
        <div style={{ marginBottom: "0.5rem",}}>
          <span style={{ color: "blue", cursor: "pointer",}}>
            {place.description}
          </span>
          <span style={{ color: "#333", fontSize: "0.75rem",}}>{`(${place.place_id})`}</span>
          <span> - {place.types.join(", ")}</span>
        </div>
      ))}
    </div>
  );
}


Creating a Smart Address Search with Google Maps API and React

根據預測,我們對 3 個領域感興趣:

  1. 地點全名。
  2. 地點 ID。
  3. 地點類型 - 實體所屬類型的陣列。您可以在此處找到完整的類型清單。我們使用它們進行額外的結果過濾。

第 3 步:完善自動完成結果

AutocompleteService 介面有大量輸入,可以讓搜尋更加準確。

Field componentRestrictions 讓我們可以將搜尋結果縮小到特定的國家。它最多支援 5 個國家/地區,並要求國家/地區代碼符合 ISO 3166-1 Alpha-2 標準。您可以在這裡找到國家/地區代碼清單。


    const { predictions } = await autocomplete.getPlacePredictions({
      ...options,
      input: query,
      componentRestrictions: {
        country: ["gb"],
      },
    });


為了讓我們的欄位不會讓使用者感到困惑,我們需要從搜尋結果中排除公園、機場等地方。自動完成服務有一個欄位類型來指定要傳回的預測類型。 但 AutocompleteService 只允許一種類型


    const { predictions } = await autocomplete.getPlacePredictions({
      ...options,
      input: query,
      componentRestrictions: {
        country: ["gb"],
      },
      types: ["geocode"],
    });


  • 地理編碼類型指示地點自動完成服務僅返回地理編碼結果,而不是業務結果

但它也包括更大的行政實體,如城市或街道。我們需要用戶選擇準確的地址。

  • 地址指示地點自動完成服務僅回傳具有精確地址的地理編碼結果

明白了!這就是我們所需要的,對吧? ....基本上,是的。但是,它不允許用戶透過郵遞區號進行搜索,這對我們來說是常見的情況。

因此,為了透過街道名稱和郵遞區號獲得精確的搜尋結果,我們編寫了一個自訂過濾器。感謝 StackOverflow 的靈感。


export const filterPredictions = (
  results: Array<google.maps.places.AutocompletePrediction>
): Array<google.maps.places.AutocompletePrediction> =>
  results.filter(({ types }) => {
    // Keep predictions that are street addresses or postal codes
    if (types.includes("street_address") || types.includes("postal_code")) {
      return true;
    }
    // For geocode types, check for building numbers (premise/subpremise)
    if (types.includes("geocode")) {
      return types.some((type) => ["premise", "subpremise"].includes(type));
    }
    return false; // Filter out irrelevant types
  });


如果結果包含街道地址或郵遞區號,我們假設它是正確的結果。
如果它具有地理編碼類型,我們會檢查前提或子前提(簡而言之,建築物編號或名稱)。有關類型的更多信息,您可以在此處閱讀。

我們所取得的成果:

Creating a Smart Address Search with Google Maps API and React

第 4 步:使用地理編碼器獲取地址詳細信息

AutocompleteService 僅返回搜尋預測,而不返回我們需要的地點詳細資訊。但是,透過地點 ID 和地理編碼器,我們可以獲得諸如確切地址、國家/地區、郵遞區號和座標等詳細資訊。
Geocoder 最初是為了在地址和座標之間轉換而創建的,但它完全滿足了我們的需求。
如果您需要有關該地點的其他資訊(例如評論和評論),可以使用 Places API。

讓我們為鉤子添加一個新方法:


// Function to get detailed information about a place using its place id
const getPlaceById = async (
  placeId: string // The place_id from the AutocompleteService
): Promise<google.maps.GeocoderResult | null> => {
  const geocoder = new google.maps.Geocoder(); // Create a new instance of Geocoder

  try {
    const { results } = await geocoder.geocode({ placeId });
    // Return the first result
    return results[0];
  } catch {
     // In case of error, return null
    return null;
  }
};


為了統一存在不同行政層級和實體的縣之間的結果,Google 使用位址組件結構。讓我們來看一個例子:

Creating a Smart Address Search with Google Maps API and React
To format the address, we need the Baker Street 221B, NW1 6XE, London (street_number route, postal_code, locality). But, in some cases, the keys structure might differ. To cover it we made an unified serializer:


// Helper function to extract a specific address component by its type (e.g., street_address, postal_code)
export const pickAddressComponentByType = (
  result: google.maps.GeocoderResult,
  type: Array<string>
): string =>
  result.address_components.find((component) =>
    component.types.some((componentType) => type.includes(componentType))
  )?.long_name || "";

// Function to serialize the geocoded result into a structured format
export const serializeGeocoderResult = (
  result: google.maps.GeocoderResult
): TFormatedGeocoderResult => ({
  formattedAddress: result.formatted_address,
  streetAddress: pickAddressComponentByType(result, [
    "street_address",
    "premise",
    "route",
  ]),
  streetNumber: pickAddressComponentByType(result, ["street_number"]),
  city: pickAddressComponentByType(result, [
    "locality",
    "postal_town",
    "administrative_area_level_2",
  ]),
  country: pickAddressComponentByType(result, ["country"]),
  state: pickAddressComponentByType(result, ["administrative_area_level_1"]),
  postalCode: pickAddressComponentByType(result, ["postal_code"]),
  latitude: result.geometry.location.lat(),
  longitude: result.geometry.location.lng(),
});


Notice, that we verified it only for Great Britain. So maybe you might need to enhance it for your specific cases.

Improvements for Google Maps Autocomplete

  1. Add the input debounce and minimum characters restriction to reduce the number of requests. Debouncing ensures that the API is only called after a certain delay, helping to reduce unnecessary requests as the user types. You can check these improvements in DEMO Sandbox.
  2. If you're open in your budget, you can fetch all of the places by their id and show users the options in the format you need, but not in the Google Autocomplete format.

Conclusions: Smart Address Search

In this article, I have shown how we can use different Google Maps API's to build address fields, that can replace full address forms and drastically reduce the time users need to spend on it, reducing the number of mistakes on the users' side.

Check out the DEMO sandbox, but don’t forget to set your own GOOGLE_MAPS_API_KEY.

Feel free to send your questions and suggestions in comments. I'll be glad for any conversations??.

以上是使用 Google Maps API 和 React 建立智慧型地址搜尋的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn