Gatsby 404 Page is complaining about Google Maps

Viewed 100

I am wondering why my 404 page is getting conflicted with my map even though there is no map on my 404 page. I have the following code for my Maps.js:

import React from "react"
import MapMarker from "../assets/images/logos/map-marker.png"

if (typeof window !== 'undefined') {
    window.initMap = function() {
        const map = new window.google.maps.Map(document.getElementById('map'), {
        center: {
            lat: 11.1463554,
            lng: 110.5245996
        },
        zoom: 10,
        styles: [{"featureType":"water","elementType":"geometry","stylers":[{"color":"#d3d3d3"},{"lightness":50}]},{"featureType":"landscape","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":20}]},{"featureType":"road.highway","elementType":"geometry.fill","stylers":[{"color":"#ffffff"},{"lightness":17}]},{"featureType":"road.highway","elementType":"geometry.stroke","stylers":[{"color":"#ffffff"},{"lightness":29},{"weight":0.2}]},{"featureType":"road.arterial","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":18}]},{"featureType":"road.local","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":16}]},{"featureType":"poi","elementType":"geometry","stylers":[{"color":"#f5f5f5"},{"lightness":21}]},{"featureType":"poi.park","elementType":"geometry","stylers":[{"color":"#dedede"},{"lightness":21}]},{"elementType":"labels.text.stroke","stylers":[{"visibility":"on"},{"color":"#ffffff"},{"lightness":16}]},{"elementType":"labels.text.fill","stylers":[{"saturation":50},{"color":"#000000"},{"lightness":40}]},{"elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"geometry","stylers":[{"color":"#f2f2f2"},{"lightness":19}]},{"featureType":"administrative","elementType":"geometry.fill","stylers":[{"color":"#4c4c4c"},{"lightness":20}]},{"featureType":"administrative","elementType":"geometry.stroke","stylers":[{"color":"#4c4c4c"},{"lightness":17},{"weight":1.2}]}]
      })

      new window.google.maps.Marker({
        position: { lat: 123.1463554, lng: 123.5245996 },
        icon: MapMarker,
        animation: window.google.maps.Animation.BOUNCE,
        map: map
    });
    }
  }

  

const Map = () => {
  return (
    <div id="map-container" data-aos="fade-up">
        <div className="container-fluid">
            <div className="row">
                <div className="col-lg-12 col-12 pl-0 pr-0">
                    <div className="google-map">
                        <div id="map"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
  )
}

export default Map

And I have this code on my /pages/404.js:

import React from "react"
import { Link } from "gatsby"
import ErrorImg from "../assets/images/header/404.png"
import Preloader from "../components/Preloader"
import Layout from "../components/Layout"
import PageBanner from "../components/PageBanner"

const Error = () => {
   return (
      <>
      <Preloader />
      <Layout>
      <PageBanner title="404 Not Found" />
        <div class="blog-section section-padding">
            <div className="container">
                <div className="row">
                    <div className="col-lg-12">
                        <img src={ErrorImg} className="d-block mx-auto" />
                        <h1 className="not-found text-center center-block mt-20">404 Not Found</h1>

                        <p className="text-center mt-20">It seems like you are lost. The page you were looking for doesn't exist, isn't available or was loading incorrectly. <br/>
                            Perhaps you can return back to the homepage and see if you can find what you are looking for. </p>

                            <div className="btn-group mt-30 d-flex justify-content-center align-content-center">
                                <Link data-wipe-normal="GO BACK TO HOMEPAGE" to="/">GO BACK TO HOMEPAGE</Link>
                            </div>
                    </div>
                </div>
            </div>
        </div>
        </Layout>
    </>
   )
}

export default Error

I was wondering whenever I visit the 404 page it's always returning this:

×
Map: Expected mapDiv of type Element but was passed null.
▶ 3 stack frames were collapsed.
./src/components/Map.js.window.initMap
C:/Users/Rean/Desktop/gatsby/src/components/Map.js:6
  3 | 
  4 | if (typeof window !== 'undefined') {
  5 |   window.initMap = function() {
> 6 |       const map = new window.google.maps.Map(document.getElementById('map'), {
  7 |       center: {
  8 |           lat: 15.1463554,
  9 |           lng: 120.5245996

Any idea what's causing this and how to fix it? Been hovering with this for a couple time. Please help

1 Answers

This is because you are never unmounting your Map component and when you navigate to another page (no matter that is 404, it would happen with everyone) it's complaining about that line. Because all the components share the routing, and the code of your map is not being rendered inside the component, it's never unmounted when the component is disposed.

There are a few things in your code, among the issue. You are attacking directly the DOM, however, the reason why you are using React, is to generate a virtual DOM to avoid that kind of high-performance operations. Real DOM operations have a high-impact on web performance as jQuery does. You can achieve the same result using some hooks.

Change your Map component to something like this:

import React, {useRef, useEffect} from "react"
import MapMarker from "../assets/images/logos/map-marker.png"

const Map = () => {
 const map=useRef(null);

  useEffect(()=>{

    if(typeof window !== "undefined"){
      window.initMap = function() {
   const map = new window.google.maps.Map(map.current, {
        center: {
            lat: 11.1463554,
            lng: 110.5245996
        },
        zoom: 10,
        styles: [{"featureType":"water","elementType":"geometry","stylers":[{"color":"#d3d3d3"},{"lightness":50}]},{"featureType":"landscape","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":20}]},{"featureType":"road.highway","elementType":"geometry.fill","stylers":[{"color":"#ffffff"},{"lightness":17}]},{"featureType":"road.highway","elementType":"geometry.stroke","stylers":[{"color":"#ffffff"},{"lightness":29},{"weight":0.2}]},{"featureType":"road.arterial","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":18}]},{"featureType":"road.local","elementType":"geometry","stylers":[{"color":"#ffffff"},{"lightness":16}]},{"featureType":"poi","elementType":"geometry","stylers":[{"color":"#f5f5f5"},{"lightness":21}]},{"featureType":"poi.park","elementType":"geometry","stylers":[{"color":"#dedede"},{"lightness":21}]},{"elementType":"labels.text.stroke","stylers":[{"visibility":"on"},{"color":"#ffffff"},{"lightness":16}]},{"elementType":"labels.text.fill","stylers":[{"saturation":50},{"color":"#000000"},{"lightness":40}]},{"elementType":"labels.icon","stylers":[{"visibility":"off"}]},{"featureType":"transit","elementType":"geometry","stylers":[{"color":"#f2f2f2"},{"lightness":19}]},{"featureType":"administrative","elementType":"geometry.fill","stylers":[{"color":"#4c4c4c"},{"lightness":20}]},{"featureType":"administrative","elementType":"geometry.stroke","stylers":[{"color":"#4c4c4c"},{"lightness":17},{"weight":1.2}]}]
      })

      new window.google.maps.Marker({
        position: { lat: 15.1463554, lng: 120.5245996 },
        icon: MapMarker,
        animation: window.google.maps.Animation.BOUNCE,
        map: map
    });
      }

    }

    return () => map.current=null; // change it to map = null if don't work

  }, [])
  


  return (
    <div id="map-container" data-aos="fade-up">
        <div className="container-fluid">
            <div className="row">
                <div className="col-lg-12 col-12 pl-0 pr-0">
                    <div className="google-map">
                        <div id="map" ref="map"></div>
                    </div>
                </div>
            </div>
        </div>
    </div>
  )
}

export default Map

Note: it's difficult to guess how the code will behave without a sandbox, but this is the direction to follow.

Using useRef hook and applying a valid reference, you can replicate the same behavior as document.getElementbyId without pointing the real DOM. Your object is inside map.current (because the reference name is map). Initially is set to null to avoid possibly memorized references across the application on React's rehydration.

The useRef hook is applied with useEffect with empty deps ([]). The useEffect with empty dependencies, will be triggered once the DOM tree is loaded, so that will ensure that your reference is created at the moment you are requesting it.

The return statement at the end of the useEffect will be triggered when the component is unmounted automatically, so at that point, you have to set the reference back to null

Related