首页  >  文章  >  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