DEV Community

Welly
Welly

Posted on • Edited on

✨ Introducing use-places-autocomplete: React hook for Google Maps Places Autocomplete

Yooo guys! with use-places-autocomplete you can build your own places autocomplete UI like the following demo in 10 minutes, no kidding 😉

demo

⚡️ Try yourself: https://use-places-autocomplete.netlify.app

Features

  • 🧠 Provides intelligent places suggestions powered by Google Maps Places API.
  • 🎣 Builds your own customized autocomplete UI by React hook.
  • 🔧 Utility functions to do geocoding and get geographic coordinates using Google Maps Geocoding API.
  • 🤑 Built-in cache mechanism for you to save the cost of Google APIs.
  • 💰 Built-in debounce mechanism for you to lower the cost of Google APIs.
  • 🚀 Supports asynchronous Google script loading.
  • 📜 Supports TypeScript type definition.
  • ⌨️ Builds a UX-rich component (e.g. WAI-ARIA compliant and keyword support) via comprehensive demo code.
  • 🦔 Tiny size (~ 1.7KB gzipped). No external dependencies, aside for the react.

How does it work?

First, use the script tag to load the library in your project.



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


Enter fullscreen mode Exit fullscreen mode

Start to build our component. Check the API out to learn more.



import usePlacesAutocomplete, {
  getGeocode,
  getLatLng,
} from "use-places-autocomplete";
import useOnclickOutside from "react-cool-onclickoutside";

const PlacesAutocomplete = () => {
  const {
    ready,
    value,
    suggestions: { status, data },
    setValue,
    clearSuggestions,
  } = usePlacesAutocomplete({
    requestOptions: {
      /* Define search scope here */
    },
    debounce: 300,
  });
  const ref = useOnclickOutside(() => {
    // When user clicks outside of the component, we can dismiss
    // the searched suggestions by calling this method
    clearSuggestions();
  });

  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) => {
        const { lat, lng } = getLatLng(results[0]);
        console.log("📍 Coordinates: ", { lat, lng });
      });
    };

  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 ref={ref}>
      <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>
  );
};


Enter fullscreen mode Exit fullscreen mode

Easy right? This is the magic of the usePlacesAutocomplete ✨. I just show you how does it work via the minimal example. However there're more things you can do for a UX rich autocomplete component, like WAI-ARIA compliant and keyword support as my demo (check the code), a keyword clear button, search history etc.

💡 react-cool-onclickoutside is my other hook library, which can help you handle the interaction of user clicks outside of the component(s).


Thanks for reading, for more usage details checkout the project's GitHub page: https://github.com/wellyshen/use-places-autocomplete

You can also install this package is distributed via npm.



$ yarn add use-places-autocomplete
# or
$ npm install --save use-places-autocomplete


Enter fullscreen mode Exit fullscreen mode

When working with TypeScript you need to install the @types/googlemaps as a devDependencies.



$ yarn add --dev @types/googlemaps
# or
$ npm install --save-dev @types/googlemaps


Enter fullscreen mode Exit fullscreen mode

Top comments (15)

Collapse
 
prissvi profile image
PrissVI

I am trying to write tests (with Jest and Enzyme) for the demo, but the data array is always empty (and status is not "OK")... Any ideas on how to solve the problem or where to find tests of the demo ?

Collapse
 
wellyshen profile image
Welly

You can mock the Google Map API like this: github.com/wellyshen/use-places-au...

Collapse
 
prissvi profile image
PrissVI • Edited

These are test for the package that I am using ('use-places-autocomplete'), but I want to test my own implementation (which I used this package for)

Thread Thread
 
wellyshen profile image
Welly • Edited

You can use jest mock functions to mock this library and let it responses the status and data that you want.

Thread Thread
 
wellyshen profile image
Welly

If you still don't know how to do it, feel free to leave an issue on the repo.

Collapse
 
eminqasimov profile image
Emin Qasimov • Edited

hi, thanks for this amazing hook
I have a question, How can i integrate this hook with useScript -usehooks.com/useScript/
to load google map script asyncly?
I get below error

'> 💡use-places-autocomplete: Google Maps Places API library must be loaded. See: github.com/wellyshen/use-places-au...';

Collapse
 
chakandinakira profile image
Lloyd

I am getting the same error, has anyone found a solution for this?

Collapse
 
glacian22 profile image
Abram Thau

Hi Welly, this is really nicely designed! One concern though, you're using a script tag to bring in the google maps api, but that exposes the API key to the user. Any ideas on how to keep the key safe?

Collapse
 
wellyshen profile image
Welly

Google has provided many way to limit the usage of the API key. You can configure it via Google Cloud Console (console.cloud.google.com)

Collapse
 
prettydev profile image
Max

Sometimes the "ready" is false, so the input is disabled. How to solve this problem?

Collapse
 
wellyshen profile image
Welly

Can you give me an open issue with a minimal reproduced repo, thank you.

Collapse
 
trapsibot profile image
Trapsi Bot

Hi Welly , its really nice but while using the package I can't limit to one particular country is there any possible way ?

Collapse
 
chanwkkk profile image
Yingqi Chen

Hey Welly that's cool! But do you know if I can use it with Gatsby(a react based language)?

Collapse
 
olegmalyarenko profile image
olegmalyarenko

Your demo isn't working

Collapse
 
wellyshen profile image
Welly

Fixed