Search code examples
ruby-on-railsreactjsgoogle-mapsgoogle-maps-markersgoogle-maps-react

Google maps react only displaying marker of last rendered object from state array


I'm having an issue with rendering google map markers from a state array. Only the last rendered marker is shown although all of the markers are listed in react components

I am using google-maps-react to display a location with many markers representing bookclubs. I fetch the addresses for my markers from a rails API, loop them into a geocoder and set the state within the loop. Each object within the state has the bookclubs lat, lng and data.

I receive the center maps location via form. the data in the form goes through the geocoder and is set to state for the map.

When I add markers using data from state.markers only the last coded marker will show up. This applies when I loop through state.markers or not.

import React, { Component } from "react";
import { Map, InfoWindow, Marker, GoogleApiWrapper } from "google-maps-react";

class GoogleMaps extends Component {
  constructor(props) {
    super(props);
    this.state = {
      markers: [],
      lat: null,
      lng: null,
      showingInfoWindow: false,
      activeMarker: {},
      selectedPlace: {}
    };
  }

  componentDidMount() {

    fetch("RAILS API ROUTE", {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bearer " + sessionStorage.JWT
      }
    })
      .then(e => e.json())
      .then(data => {
        let bookClubs = data.book_clubs;
        console.log("let", bookClubs);
        bookClubs.forEach(club => {
          const googleMapsClient = require("@google/maps").createClient({
            key: "API KEY",
            Promise: Promise
          });
          googleMapsClient
            .geocode({
              address: `${(club.address.address_line1,
              club.address.address_line2,
              club.address.city)}`
            })
            .asPromise()
            .then(response => {
              console.log("response!!!!!!!!!!!!!", response.json.results);
              let info = {
                lat: response.json.results[0].geometry.location.lat,
                lng: response.json.results[0].geometry.location.lng,
                bookClub: club
              };
              let dataCopy = this.state.markers
              dataCopy.push(info);

              this.setState(
                {
                  markers: dataCopy
                },
                () => {
                  console.log("State::::", this.state.markers);
                }
              );
            });
        });

      })
      .catch(error => console.error("Error:", error));
  }

  onMarkerClick = (props, marker, e) =>
    this.setState({
      selectedPlace: props,
      activeMarker: marker,
      showingInfoWindow: true
    });

  onMapClicked = props => {
    if (this.state.showingInfoWindow) {
      this.setState({
        showingInfoWindow: false,
        activeMarker: null
      });
    }
  };



  render() {
    return (
      <div
        style={{ display: "flex", flexDirection: "flexEnd", flexWrap: "wrap" }}
      >




        {this.state.lat != null && (
          <Map
            onClick={this.onMapClick}
            google={this.props.google}
            initialCenter={{
              lng: this.state.lng,
              lat: this.state.lat
            }}
            center={{
              lng: this.state.lng,
              lat: this.state.lat
            }}
            containerStyle={{
              width: "100%",
              height: "250px",
              position: "relative"
            }}
            style={{
              height: "35vh",
              width: "35vh",
              display: "flex",
              justifyContent: "flexEnd"
            }}
            zoom={14}
          >


            {this.state.markers.map((e, i) => (
              <Marker
                key={i}
                onClick={this.onMarkerClick}
                position={{ lat: e.lat, lng: e.lng }}
                title={`${e.bookClub.address.address_line1}  ${e.bookClub.address.address_line2}`}
                name={e.bookClub.address.city}
              />
            ))}

            <InfoWindow
              marker={this.state.activeMarker}
              visible={this.state.showingInfoWindow}
            >
              <div>
                <h1>{this.state.selectedPlace.name}</h1>
              </div>
            </InfoWindow>
          </Map>
        )
        }
      </div>
    );
  }
}
export default GoogleApiWrapper({
  apiKey: "API KEY"
})(GoogleMaps);



Solution

  • The problem was that I was adding commas while inserting data into my geocoder.

     googleMapsClient
                .geocode({
                  address: `${(club.address.address_line1,
                  club.address.address_line2,
                  club.address.city)}
    

    I removed the commas and made the code like below, which solved my problem.

    googleMapsClient
                .geocode({
                  address: `${club.address.address_line1} ${club.address.address_line2} ${club.address.city} `
                })
    

    The reason only the last marker showed is that the geocoder gave all the markers the same lat and lng when I had commas. This caused all of them to cover each other in the same location while the last rendered marker was left on top.