DEV Community

Thomas Ledoux
Thomas Ledoux

Posted on • Edited on • Originally published at thomasledoux.be

Easy way to integrate Google Maps in React

More often than not, you will be asked to add a map coming from Google Maps to websites you are developing.
This might seem like a pain to integrate in your React application, but luckily Alexey Lyakhov created a package to make it all a bit easier: React Google Maps API.
It's well documented too!

Now, let's dive into the actual code to create a component using this package!

import React from "react";
import {
  GoogleMap,
  useJsApiLoader,
  Marker,
  InfoWindow
} from "@react-google-maps/api";

type OfficeNode = {
  id: string;
  field_address: {
    locality: string;
    postal_code: string;
    address_line1: string;
    address_line2: string;
    latitude: number;
    longitude: number;
  };
};

export default function App() {
  const offices = [
    {
      id: "1",
      field_address: {
        locality: "Gent",
        postal_code: "9000",
        address_line1: "Veldstraat 1",
        address_line2: "a",
        latitude: 51.053589,
        longitude: 3.72242
      }
    },
    {
      id: "2",
      field_address: {
        locality: "Brussel",
        postal_code: "1000",
        address_line1: "Nieuwstraat 1",
        address_line2: "a",
        latitude: 50.85061,
        longitude: 4.35403
      }
    },
    {
      id: "3",
      field_address: {
        locality: "Antwerpen",
        postal_code: "2000",
        address_line1: "Meir 1",
        address_line2: "a",
        latitude: 51.21878,
        longitude: 4.40559
      }
    }
  ];
  const mapRef = React.useRef<any>(null);
  const [selectedOffice, setSelectedOffice] = React.useState<
    OfficeNode | undefined | null
  >(null);
  const { isLoaded } = useJsApiLoader({
    id: "google-map-script",
    googleMapsApiKey: "ENTER-YOUR-API-KEY-HERE"
  });
  const onLoad = React.useCallback(
    (mapInstance) => {
      const bounds = new google.maps.LatLngBounds();
      offices.forEach((office) => {
        bounds.extend(
          new google.maps.LatLng(
            office.field_address.latitude,
            office.field_address.longitude
          )
        );
      });
      mapRef.current = mapInstance;
      mapInstance.fitBounds(bounds);
    },
    [offices]
  );
  const onClickMarker = (officeId: string) => {
    setSelectedOffice(offices.find((office) => office.id === officeId));
  };
  return (
    <div className="App">
      <h1>Google maps + React</h1>
      {isLoaded ? (
        <>
          <GoogleMap
            mapContainerClassName="c-office-overview__map"
            onLoad={onLoad}
          >
            {offices.map((office) => (
              <Marker
                key={office.id}
                onClick={() => onClickMarker(office.id)}
                position={{
                  lat: office.field_address.latitude,
                  lng: office.field_address.longitude
                }}
              />
            ))}
            {selectedOffice ? (
              <InfoWindow
                position={{
                  lat: selectedOffice.field_address.latitude,
                  lng: selectedOffice.field_address.longitude
                }}
                onCloseClick={() => setSelectedOffice(null)}
              >
                <p>
                  {selectedOffice.field_address.address_line1}{" "}
                  {selectedOffice.field_address.address_line2} -{" "}
                  {selectedOffice.field_address.postal_code}{" "}
                  {selectedOffice.field_address.locality}
                </p>
              </InfoWindow>
            ) : null}
          </GoogleMap>
        </>
      ) : null}
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

So let's see what's going on here.
We import the different needed components from the library and we select the needed library (only places needed for this demo).
After this is done, we can create a Ref with the useRef hook, this will be used to store the reference to the Google Maps map.

We then use the useJsApiLoader hook to initialise the Google Maps API, passing the API key.
From the response of this hook, we can get the isLoaded boolean back, this will be used to show/hide the map in our rendering.
We also need to create an onLoad function (wrapped in a useCallback hook), this will be called by the Google Maps API once it's done initialising.
In this function we'll loop over our offices, and add positions to the bounds of our Google Map, so the map is correctly centered, and we'll assign the Google Maps instance to our Ref we created earlier.

In our rendering, it's all pretty straightforward. We render our map once the isLoaded boolean is true.
We render a marker for every office, and add an onClick listener to select the office when the marker is clicked.

We also have a check in the code to see if selectedOffice, when an office is selected we want to use the InfoWindow from Google Maps to show some details of the office.
When the close button is clicked, the selectedOffice will be cleared.

And that's it!
I hope this was helpful.
I might write a follow-up article where I explain how to search for addresses with Google Maps Places, and how to search the closest office to the address. This would also include working with the built-in geolocation API in the browsers.
If you'd be interested in this, leave a comment :-)

Source code can be found on Codesandbox (you still need to enter a Google Maps API key, I can't give out mine since I'd get charged :D)

Top comments (6)

Collapse
 
boris74000 profile image
Boris74000

Amazing, it works !!

here is my very first code codesandbox.io/s/openclassrooms-pr...
What is the difference ?
Can you explain me why bounds = -180 180 -1 1 ?

Thank you so much, I will be able to move forward on my project.

Collapse
 
thomasledoux1 profile image
Thomas Ledoux

I guess this is caused because you didn't add anything to your bounds yet. If you look at my initial example, I add all my offices to the bounds using a for each loop.
Hope that helps!

Collapse
 
boris74000 profile image
Boris74000 • Edited

Hi Thomas, great article !

I use this code but when i print bounds variable, i get this result on screenshot.
dev-to-uploads.s3.amazonaws.com/up...
If i zoom or drag the map, the result is the same.
I expected to have a result like 45.90202596575145, 6.126262142126459.

I want to show in a list next to the map, the restaurant markers visible in current viewport.

Collapse
 
thomasledoux1 profile image
Thomas Ledoux

Hey Boris, thank you!
Do you have a codesandbox/codepen with the code?
Would be easier to debug :-)

Collapse
 
boris74000 profile image
Boris74000 • Edited

I use this code (npmjs.com/package/@react-google-ma...)
because i don't know TypeScript.
My codesandbox codesandbox.io/s/quirky-williamson...

Collapse
 
thomasledoux1 profile image
Thomas Ledoux

You could try something like this: codesandbox.io/s/lively-sun-8v5r8?...
Look at the dragEnd function where I'm logging the latitude of the current center of the map (that's what the user is looking at at this moment)