Search code examples
reactjsgoogle-mapsgoogle-maps-react

I'm trying to number my Markers and show InfoWindow with google-maps-react


I can't seem to be able to show the index from my json to google-maps-react, I can see all the markers mapped out, but they show the default marker with no window popped out. Here is the code with the <InfoWindow> placed, react was complaining I have to put a parent div, when I do, I don't see any markers currently.

My car2go json is mapping correctly, just not printing out name={content.name}.

My map.js component:

import React, { Component } from "react";
import Car2go from "../data/car2go/vehicles.json";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";

export class MapContainer extends Component {
  constructor(props) {
    super(props);
    this.onMarkerClick = this.onMarkerClick.bind(this);
    this.state = {
      showingInfoWindow: false,
      activeMarker: {},
      selectedPlace: {},
      name: null
    };
  }
  onMarkerClick(props, marker, e) {
    this.setState({
      selectedPlace: props,
      activeMarker: marker,
      showingInfoWindow: true
    });
  }
  render() {
    const google = window.google;
    const style = {
      width: "70%",
      height: "70%",
      margin: "0 auto"
    };
    //const google = window.google;
    return (
      <Map
        google={this.props.google}
        style={style}
        initialCenter={{
          lat: 53.59301,
          lng: 10.07526
        }}
        zoom={12}
        onClick={this.onMapClicked}
      >
        {Car2go.placemarks.map((content, index) => {
          return (
            <div>
              <Marker
                title={index}
                name={content.name}
                position={{
                  lat: content.coordinates[1],
                  lng: content.coordinates[0]
                }}
                onClick={this.onMarkerClick}
                name={content.name}
              />

              <InfoWindow
                marker={this.state.activeMarker}
                visible={this.state.showingInfoWindow}
              >
                <div>
                  <h1>{this.state.selectedPlace.name}</h1>
                </div>
              </InfoWindow>
            </div>
          );
        })}
      </Map>
    );
  }
}

export default GoogleApiWrapper({
  apiKey: "xxxxx"
})(MapContainer);

Solution

  • I guess the React is complaining with error which is similar to this one:

    React does not recognize the mapCenter prop on a DOM element

    If so, the root cause of this error is related with wrapping Marker component with a div container:

    <div>
        <Marker 
           ...  
        />
    </div>
    

    and the way how google-maps-react Map component renders children elements. In that case Map props are transferred to div element instead of Marker component. For a more detail refer Unknown Prop Warning article.

    To circumvent this error the following approach could be considered:

    • replace div container with React.Fragment
    • explicitly transfer map props to Marker component

    Here is an example:

    class Map extends Component {
      constructor() {
        super();
        this.state = {
          map: null
        };
        this.handleMapReady = this.handleMapReady.bind(this);
      }
    
      handleMapReady(mapProps, map) {
        this.setState({ map: map });
      }
    
      render() {
        return (
          <Map
            google={this.props.google}
            className={"map"}
            initialCenter={this.props.center}
            zoom={this.props.zoom}
            onReady={this.handleMapReady}
          >
            {this.state.map &&
              places.map((place, i) => {
                const mapProps = Object.assign({}, this.props);
                mapProps.map = this.state.map;
                return (
                  <React.Fragment key={i}>
                    <Marker
                      {...mapProps}
                      onClick={this.handleMarkerClick}
                      position={place.position}
                      placeIndex={i}
                      name={place.name}
                    />
                  </React.Fragment>
                );
              })}
          </Map>
        );
      }
    }
    

    But instead of changes described above I would propose another approach, in particular to create a single instance of InfoWindow component and manage it as demonstrated below:

    <Map
        google={this.props.google}
        className={"map"}
        initialCenter={this.props.center}
        zoom={this.props.zoom}
      >
        {places.map((place, i) => {
          return (
            <Marker
              key={i}
              onClick={this.handleMarkerClick}
              position={place.position}
              placeIndex={i}
              name={place.name}
            />
          );
        })}
        <InfoWindow
          marker={this.state.activeMarker}
          visible={this.state.showingInfoWindow}
          onClose={this.handleClose}
        >
          <div>{this.state.selectedPlace.name}</div>
        </InfoWindow>
      </Map>
    

    Here is a demo