DEV Community

loading...

3 gotchas when setting up Google Maps API with Next.js and ESLint

masakudamatsu profile image Masa Kudamatsu Originally published at masakudamatsu.Medium Updated on ・5 min read

Key lines of code in this article, written in calligraphic style
I've set up Google Maps JavaScript API for my Next.js app. The API documentation on how to get started (Google 2021) is very well-written, but I encountered a few gotchas when the API is used together with Next.js and also ESLint. Let me take note of them below for your information (and for my future self).

Gotcha #1: CSS

TL;DR

Add the following CSS declaration:

#__next {
  height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Detail

To show a Google Map across the entire browser window, Google (2021) recommends the following CSS code:

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
#map {
  height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

where #map is the id for the container element in which a Google Map will be shown.

With Next.js, however, the #map container will not be a direct child of the body element. There will be another div with #__next as its id attribute:

<html>
  <body>
    <div id="__next">
      <div id="map"></div>
    </div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

By default, the #__next container has height:auto. As it doesn't recognize any content, the height will be zero. So the following CSS declaration

#map {
  height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

will set the height of the #map container to be 100% of zero. That is, zero. As a result, a Google Map inside the container won't be shown.

A workaround is suggested by SkyzohKey (2018):

#__next {
  height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

This will ensure that the #__next container's height will be 100% of the body element's height, which is in turn 100% of the html element's height, which is in turn 100% of the browser window height.

  • Incidentally, I haven't found any documentation saying the height:100% will refer to the browser window height when it's applied to the html element. Let me know if you know where to look for.

Consequently, the #map container's height will be 100% of the #__next container, that is, the browser window height.

Gotcha #2: React hooks

TL;DR

Compose the pages/index.js as follows:

// pages/index.js

import {useEffect, useRef} from 'react';
import {Loader} from '@googlemaps/js-api-loader';

function HomePage() {
  const googlemap = useRef(null);

  useEffect(() => {
    const loader = new Loader({
      apiKey: 'yourAPIkey',
      version: 'weekly',
    });
    let map;
    loader.load().then(() => {
      map = new google.maps.Map(googlemap.current, {
        center: {lat: -34.397, lng: 150.644},
        zoom: 8,
      });
    });
  });
  return (
    <div id="map" ref={googlemap} />
  );
}

export default HomePage;
Enter fullscreen mode Exit fullscreen mode

Detail

Google (2021) suggests the following JavaScript code to embed a Google Map:

  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: -34.397, lng: 150.644 },
    zoom: 8,
  });
Enter fullscreen mode Exit fullscreen mode

where the #map container is referenced with document.getElementById("map"). An experienced React user can immediately tell that this should be replaced with the useRef hook.

  • For why we should use useRef() instead of document.getElementById(), see Farmer (2018).

In addition, when we need to refer to the element during the initial rendering of a React component, we should use the useEffect hook. So all the JavaScript code to embed a Google Map needs to be written inside the useEffect hook block.

This is a technique I've learned for using the canvas element with React. See Kudamatsu (2020) (see Step 4) for detail.

Gotcha #3: Handling ESLint error

TL;DR

Add the following line immediately before creating a map instance:

const google = window.google;
Enter fullscreen mode Exit fullscreen mode

Detail

The code in the previous two sections will do render a Google Map. But if you use ESLint, it throws an error because of this line:

map = new google.maps.Map(googlemap.current, {...});
Enter fullscreen mode Exit fullscreen mode

The object called google is used without being defined. ESLint doesn't like it. And it is a compile error. So you cannot tell ESLint to ignore this line of code (ESLint 2019).

A workaround is suggested by Abramov (2017). He explains why ESLint complains:

"... people commonly misunderstand the difference between local variables, imported modules, and global variables, and so we want to always make it clear in the code when you use a global variable."

So to make it clear that google is a global variable, we should write the useEffect block of code in the following way:

  useEffect(() => {
    const loader = new Loader({
      apiKey: 'yourAPIkey',
      version: 'weekly',
    });
    let map;
    loader.load().then(() => {
      const google = window.google; // ADDED
      map = new google.maps.Map(googlemap.current, {
        center: {lat: -34.397, lng: 150.644},
        zoom: 8,
      });
    });
  });
Enter fullscreen mode Exit fullscreen mode

The window.google is undefined until the Google API library is referenced (Marcus 2018). So it has to be inside the loader.load().then() block.

Summary

Your pages/index.js should look like this:

// pages/index.js

import {useEffect, useRef} from 'react';
import {Loader} from '@googlemaps/js-api-loader';

function HomePage() {
  const googlemap = useRef(null);

  useEffect(() => {
    const loader = new Loader({
      apiKey: 'yourAPIkey',
      version: 'weekly',
    });

    let map; 
    loader.load().then(() => {
      const google = window.google;
      map = new google.maps.Map(googlemap.current, {
        center: {lat: -34.397, lng: 150.644},
        zoom: 8,
      });
    });
  });

  return (
    <div id="map" ref={googlemap} />
  );
}

export default HomePage;
Enter fullscreen mode Exit fullscreen mode

Then add the following CSS declarations:

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#__next {
  height: 100%;
}

#map {
  height: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Hope this helps!

References

Dan Abramov (2017) “An answer to ‘google is not defined in react app using create-react-app’”, Stack Overflow, May 1, 2017.

ESLint (2019) “Disabling Rules with Inline Comments”, ESLint User Guide, Dec. 1, 2019.

Farmer, Andrew H. (2018) “Why to use refs instead of IDs”, JavaScript Stuff, Jan 27, 2018.

Google (2021) “Overview”, Maps JavaScript API Guides, Feb. 10, 2021.

Kudamatsu, Masa (2020) “How to use HTML Canvas with React Hooks — Web Dev Survey from Kyoto”, medium.com, Dec. 9, 2020.

Marcus, Scott (2018) “A comment to ‘window.google is undefined in react?’”, Stack Overflow, Apr. 25, 2018.

SkyzohKey (2018) “An answer to ‘Nextjs:How to change css of root div __next on specific page?’”, Stack Overflow, Dec. 5, 2018.

Discussion (0)

pic
Editor guide