This is a short tutorial on how to successfully implement Google Maps using a handy library created by Google's own Developer Relations Engineer @jpoehnelt and maintained by the community. We'll have a map with a search and a location marker by the end of it. All using the native Google Maps API with the help of @googlemaps/react-wrapper.

What you will need:

If you want to see the finished project, the code is available in this repository.

Why this library?

If you visit the library documentation, you won't see much. It has a simple and straightforward example showing how to render a map in your app.

Under the hood, though, it has two very important characteristics:

Using its render strategy, it's even possible to show a loader when the script is not loaded yet.

Implementing the code

From zero...

To start our little Maps adventure, we'll create a simple component:

Awesome, what might seem like a boring page with no content... is also a fertile field for ambitious creation!


First, add the library to your project:

If you use Typescript (I do!), also add the types:

If you use Typescript (I do!), also add the types:

If you don't do Typescript — you should — this tutorial is harder to copy-paste but simple to follow up. Just ignore the types 😁

Here comes the wrapper

The library tells us to add a Wrapper component to our code to load Google's API script and render the map. Let's do it in a separate Map component.

(I'll also add some CSS to this page, but you don't need to do the same, ok?)

This Wrapper is very important: it takes as props the apiKey and, in this example, a render function.

The unknown magic here is that you can call this Wrapper as many times as you want, and the Google Maps API script will only be loaded at the first call. This saves us time, processing, and money.

PS: You can't call different instances with different API keys. You'll get a console error if you try to do this.

Did you notice I mentioned a render prop but didn't use it in the last example? Well, here it comes:

The render function is simple and pratical: we can render different components depending on the status of the script loading.

I won't focus on the LOADING and FAILURE states in this tutorial, though. Use your imagination and build a beautiful loading spinner and an informative error page.

Where's the map?

So far, our page looks even more boring than before:

We still need another component to render the actual map with all its configurations. Introducing the MapComponent:

Things are getting real

Now, we need to update the parent component to pass the correct properties down the tree.

Here is where the fun actually begins: at this moment, we can access and use the whole Google Maps API, because the Wrapper from the library makes sure the API is loaded and ready.

For instance: when passing center, we could use the API constructors to build us the object we require:

This will create the center object with correct types and all.

"But Angelo, this is a silly example, as center is just an object with two properties. I could just write it, no need for this fancy constructor."

Yes, little grasshopper, you are correct. This, though, is a simple example of accessing the API constructors and using them for virtually anything the API provides.

Want to do a marker? Use the API constructors. A route? API constructor. A search? Well, guess what?

The only required CSS we're going to write

If we look at the page we're building, we'll see a beautiful... nothing.

For the map to be displayed, our div needs a fixed height. Doing so, the Map wrapper will render using the entire available space:

And that's the only CSS you will write to make this map happen. Refresh your browser, and look what's there:

Tweaking the map

You have a fully working map in your app, with the correct behaviour of any Google Map instances you see around there.

This is a lot... and I want less.

So let's use Google Maps API to disable some stuff that's cluttering our map.

That's more like it! Following the Google Maps API, I could turn off any feature I didn't want on my map.

So far, so good.

At this moment, we have a perfectly working map in our app.

So, if after the storm comes a calm, let's add some storm to our lives.

Adding a Location Search

Remember our main App file? Let's add a new component there:

Let's create a new Search.tsx component so we can handle everything location-related there.

This component will be very much like the Map.tsx: a Wrapper and a render function.

Notice, above; we have two main differences from the Map:

Important: you should add your libraries to every call of the wrapper component, so we'll update that on the Map.tsx file as well.

PS: If you are messing with Google Maps API for the first time, you need to know there are some API parts you have to allow on their console for this to work. They have different pricing , so be careful with what you do and read their docs thoroughly.

Search and you may find

One great Google Maps API tool is the Autocomplete widget. It automatically renders a search bar for us without the need for too much configuration or even UI building. It's not the most beautiful, but it works.

Let's implement it in our brand new SearchComponent:

You can see that we're setting the type of search for geocode. which, to keep it simple, means: search addresses, cities, and PO-boxes, and you will get an answer.

If you want to, we can filter even more our search parameters. Let's limit the search only to Germany.

Looking at our app now, we can search for a myriad of places but this results in no change in our map, right?

That's why the received value from the Autocomplete is not being used anywhere.

Putting things together

Let's put the reaction in this React application.

In our App.tsx, we're going to handle a coordinates state and pass it down to our Map. The setCoordinate we'll pass it down to our Search.

In summary: the search will update the map's coordinates.

Quick info on Coordinates type: when we create an object “by hand”, Google sees it as a LatLngLiteral. When we create it via the constructor, it’s assigned a LatLng type. The main difference is that the latter has more information than just latitude and longitude, but we won’t go that far in this tutorial.

The above coordinates come, by default, with a fixed location. We pass it to center as it's going to be the first coordinates rendered.

Then, in the MapComponent, we add an useEffect to recenter the map with the coordinates change (no need to recreate it, right?):

OK. Done. Now, to the second part, starting with the Search:

SearchComponent, on the other hand, is more complicated. Come with me, step by step:

UGH, it looks a lot, right?

Maybe with the code things will get easier. See below:

Now, if you go to our app and do the search again, it will hop to the correct place.

You are here

There's still one more thing that we can do here to make our app even better.

When we search for the location, there's nothing to tell us exactly where's what we search for. We have a general idea of a center, but that's it.

Let's add the final component of this exercise: the Marker.

Step by step:

To add the marker to our map, we have to do two things.

  1. Save our map instance in a state;
  2. Render our Marker if a map is present

Voilá, it’s done! hero

Going to our app and searching for a location is a breeze:

And that's it!

See the full code in this repository.

I hope you have learned a lot in this exercise and, if you learned just a little, that's also a good reason for celebration, right?

Grab your beverage of choice, select a non-healthy snack and congratulate yourself.

Share this article with your peers so they can congratulate themselves as well 😜