Alexander Forbes-Reed
Alexander Forbes-Reed

Reputation: 2975

Google Maps element is just grey in react app

I'm using the react-google-maps package for react, and for some reason when it renders it's just grey. If the responsive state changes then it does appear weirdly.

when rendered

I've wrapped the package in a custom component for re-usablility, and the code is:

import _ from 'lodash';
import exact from 'prop-types-exact';
import propTypes from 'prop-types';
import withScriptjs from 'react-google-maps/lib/async/withScriptjs';
import { GoogleMap as GMap, withGoogleMap } from 'react-google-maps';
import React, { Component } from 'react';

const apiKey = 'api_key';

const AsyncMap = _.flowRight(
    withScriptjs,
    withGoogleMap,
    )(props => (
        <GMap
            defaultCenter={props.defaultCenter}
            defaultZoom={props.defaultZoom}
            onClick={props.onClick}
            ref={props.onMapLoad}
        >
            {props.children}
        </GMap>
    ));

class GoogleMap extends Component {
    render() {
        return (
            <AsyncMap
                googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&key=${apiKey}`}
                loadingElement={<div>{'loading...'}</div>}
                {...this.props}
            />
        );
    }
}

GoogleMap.propTypes = exact({
    containerElement: propTypes.object,
    defaultCenter: propTypes.object.isRequired,
    defaultZoom: propTypes.number,
    mapElement: propTypes.object,
    onClick: propTypes.func,
});

GoogleMap.defaultProps = {
    containerElement: (<div style={{ height: '250px' }} />),
    mapElement: (<div style={{ height: '250px' }} />),
    defaultZoom: 5,
    onClick: _.noop,
};

export default GoogleMap;

And it's called like so:

<GoogleMap
    containerElement={<div className={'overnight-storage-map'} style={{ height: '250px' }} />}
    defaultCenter={storageLocation}
    defaultZoom={3}
>
    <Marker
        defaultAnimation={2}
        key={`marker-${s.id}`}
        position={storageLocation}
    />
</GoogleMap>

Upvotes: 1

Views: 2571

Answers (2)

manicmaker6
manicmaker6

Reputation: 121

New Answer - June 2023

I ran into a similar issue and found this thread in my research. I am using the @react-google-maps/api NPM package with Next.js, and the following code produced a grey map. However, I know that the map component itself was rendering, because when scrolling across the map, I still got the "Use ⌘ + scroll to zoom the map" message that you would normally get with Google Maps.

<GoogleMap
  onLoad={onLoad}
  onUnmount={onUnmount}
  mapContainerClassName='w-full h-full'
  mapTypeId='satellite'
  zoom={9}
>
</GoogleMap>

Use ⌘ + scroll to zoom the map

The solution was thankfully quite simple, but I only managed to find it by trial and error - Make sure to set the "center" property on the Map component:

<GoogleMap
  onLoad={onLoad}
  onUnmount={onUnmount}
  mapContainerClassName='w-full h-full'
  mapTypeId='satellite'
  zoom={9}
  center={{ lat: 33.8588611, lng: -84.2484869 }}
>
</GoogleMap>

And just like magic, it started loading correctly!

I hope that this answer helps somebody else down the road with the same issue as me, but where none of the other Stackoverflow answers or GitHub issues that talk about resizing seem to fix the issue.

Cheers!

Upvotes: 3

Alexander Forbes-Reed
Alexander Forbes-Reed

Reputation: 2975

The problem ended up being that this was rendered inside an accordion that wasn't expanded by default. I just wrote a function that called the native resize method on the map when the accordion is expanded/collapsed.

import _ from 'lodash';
import exact from 'prop-types-exact';
import propTypes from 'prop-types';
import withScriptjs from 'react-google-maps/lib/async/withScriptjs';
import { GoogleMap as GMap, withGoogleMap } from 'react-google-maps';
import React, { Component } from 'react';

const apiKey = 'api_key';

const AsyncMap = _.flowRight(
    withScriptjs,
    withGoogleMap,
    )(props => (
        <GMap
            defaultCenter={props.defaultCenter}
            defaultZoom={props.defaultZoom}
            onClick={props.onClick}
            ref={props.onMapLoad}
        >
            {props.children}
        </GMap>
    ));

class GoogleMap extends Component {
    constructor(props) {
        super(props);

        this.state = {
            dragged: false,
        };

        this.dragged = this.dragged.bind(this);
        this.onMapLoad = this.onMapLoad.bind(this);
        this.resize = this.resize.bind(this);
    }

    dragged() {
        this.setState({ dragged: true });
    }

    onMapLoad(map) {
        if (!map) return;

        this._map = map;
        this._mapContext = this._map.context.__SECRET_MAP_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;

        this._mapContext.addListener('drag', this.dragged);
    }

    resize() {
        window.google.maps.event.trigger(this._mapContext, 'resize');

        if (!this.state.dragged)
            this._mapContext.setCenter(this.props.defaultCenter);
    }

    render() {
        return (
            <AsyncMap
                googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=${apiKey}`}
                loadingElement={<div>{'loading...'}</div>}
                onMapLoad={this.onMapLoad}
                {...this.props}
            />
        );
    }
}

GoogleMap.propTypes = exact({
    children: propTypes.any,
    containerElement: propTypes.object,
    defaultCenter: propTypes.object.isRequired,
    defaultZoom: propTypes.number,
    mapElement: propTypes.object,
    onClick: propTypes.func,
});

GoogleMap.defaultProps = {
    containerElement: (<div style={{ height: '250px', width: '100%' }} />),
    mapElement: (<div style={{ height: '250px', width: '100%' }} />),
    defaultZoom: 5,
    onClick: _.noop,
};

export default GoogleMap;

Upvotes: 1

Related Questions