ReactJS and Google Maps - Displaying Markers

Adam Davies

I'm React newbie so maybe asking a stupid question, but this has got me perplexed. As part of my learning I'm building a three component application - a parent About, and two children (GoogleMap and MapMarkerDetails). The parent does the data coordination and one child shows a google map with two markers as default, the other child shows details of the markers when it is clicked.

I am now adding functionality to add a new marker when the map is clicked. Most of the functionality works - the maps is draw, the default markers are added, and when one of the markers is clicked, this calls a function on the parent class which updates its state and this is propagated to the MapMarkerDetails element and a simple message is displayed.

Here is the parent class which I have commented to help understanding:

import React, { Component } from 'react';
import GoogleMap from './GoogleMap'
import MapMarkerDetails from './MapMarkerDetails'

class About extends Component {

state = {
    markers: [{
        position: { lat: 51.438759, lng: -2.864514 },
        label: 'A',
        map: null,
    }, {
        position: { lat: 51.433636, lng: -2.868734 },
        label: 'B',
        map: null,
    }],
    greeting: 'HelloA'
}

showMarkerInfo = (label) => {
    this.setState({greeting: ('Hello ' + label)})
}

/* 
Adding a new Marker 
This function is called from the child element GoogleMap
However, the setState(...) dosn't seem to propogate down to the GoogleMap element.
*/
addMarker = (latlng) => {
    let newMarker = [{
        position: { lat: latlng.lat(), lng: latlng.lng() },
        label: 'New',
        map: null,
    }];

    /* Creates a new array for updating state. Is this the best way to do this */
    let markers = [...this.state.markers, ...newMarker] 
    this.setState({markers});

    console.log(this.state) // This shows the added marker
}

render() {
    return (
        <div className="container">
            <h4 className="center">About</h4>
            <MapMarkerDetails details={this.state.greeting}/>
            <GoogleMap markers={this.state.markers} clickedMarker={this.showMarkerInfo} addMarker={this.addMarker}/>
        </div>
    )
    }
}

export default About;

Here is the class that displays Google Map and the markers:

import React, { Component } from 'react';

class GoogleMap extends Component {
  constructor(props) {
    super(props);
    this.googleMapRef = React.createRef(); // Create a referance for Google Map to draw to
    console.log('Constructore')
  }

  componentDidMount(){
    console.log('componentDidMount')
    /* Create the Map */
    let googleMap = new window.google.maps.Map(this.googleMapRef.current, {
      zoom: 15,
      center: {
        lat: 51.436411,
        lng: -2.861980,
      },
      disableDefaultUI: true,
    })

    this.placeMMarkers(googleMap) // Place the markers
    this.addMapListner(googleMap) // Define a click listener to place new markers
  }

  /* Place the markers */
  placeMMarkers = (googleMap) => {
    this.props.markers.forEach((m) => {
      m.map = googleMap;
       let marker= new window.google.maps.Marker(m)
       marker.addListener('click', () => { this.props.clickedMarker(m.label); });
     }
   );
 }

 /* Map listeners */
  addMapListner = (googleMap) => {
    googleMap.addListener('click', (e) => {
      this.props.addMarker(e.latLng)
    })
  }

  render() {
    console.log('render: ' + this.props.markers) // This is showing the added markers
    return (
      <div
        id="google-map"
        ref={this.googleMapRef}
        style={{ width: '800px', height: '400px', float: 'left' }}>
      </div>
    )
  }
}

export default GoogleMap

I've added console logging to each function so I can follow what is happening.

Here is the MapMarkerDetails which displays a simple message when an marker is clicked. This all works fine.

import React, { Component } from 'react';

class MapMarkerDetails extends Component {

    render(){
        return (
            <div style={{width: '100px', height: '400px', backgroundColor: 'gray', float: 'left'}}>
                {this.props.details}
            </div>
        )
    }
}

export default MapMarkerDetails

Description of the Problem

When the user clicks on the map (not a marker) this invokes the function addMarker which is passed down from the parent About class (snippet below). In the addMarker function of About the lat/lng is passed in. This represents where the user clicked. This is converted into a marker data object, then a new array is created which contains the default markers and the new one. I'm not sure if my new array creation is done in the best way - if not let me know.

Once the new array is created, we update the components state with this.setState({markers}). I thought this would lead to a re-render() and an redrawing of the map with the added marker. But not.

addMarker = (latlng) => {
    let newMarker = [{
        position: { lat: latlng.lat(), lng: latlng.lng() },
        label: 'New',
        map: null,
    }];

    /* Creates a new array for updating state. Is this the best way to do this */
    let markers = [...this.state.markers, ...newMarker] 
    this.setState({markers});

    console.log(this.state) // This shows the added marker
}

Something happens that results in the render() function of GoogleMap being called, but only the original markers are shown. The data is passed down to the GoogleMap component because I can see the output of console.log('render: ' + this.props.markers). But how do I get ALL the markers to load?

Please advise on what is the best way to for About to pass data to GoogleMap such that it can add in the new marker.

Tom Fenech

Just like you use componentDidMount to imperatively add the markers when the map is first loaded, you should use componentDidUpdate to do the same thing when the props change. In your GoogleMap component:

componentDidUpdate() {
  this.placeMMarkers()
}

Rather than passing googleMap as an argument, I would set it as an instance variable in componentDidMount:

this.googleMap = new window.google.maps.Map(...

and then change placeMMarkers to use this.googleMap:

placeMMarkers = () => {
  this.props.markers.forEach((m) => {
    m.map = this.googleMap;
    // ...

Since you are attaching an event handler in placeMMarkers, you should also add some logic to distinguish between new markers and existing ones, to avoid adding multiple event handlers to existing markers.

In response to your question about how best to set the state, I think what you've got is fine but you don't need to put the new marker inside an array:

let newMarker = {
    position: { lat: latlng.lat(), lng: latlng.lng() },
    label: 'New',
    map: null,
};
let markers = [...this.state.markers, newMarker]

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Google Maps jQuery Marker not Displaying

分類Dev

Placing Circles instead of Markers in google maps

分類Dev

Google maps delete all markers and then create new

分類Dev

Google Maps: infobox turns up behind markers?

分類Dev

Google Maps fit markers in custom bounds

分類Dev

Google maps API markers content hide by default

分類Dev

How to hide/show groups of markers by category with Google Maps in Android?

分類Dev

Google Maps API 3 - Show All Markers on Screen, but Keep Centerpoint

分類Dev

How to get all markers in google-maps-react

分類Dev

How to Add Google Maps with Multiple Markers Showing Infowindows on Load and on Click

分類Dev

How to delete markers from my own google maps

分類Dev

Setting listeners to groups of markers using Google Maps API

分類Dev

Google Map API V3 - infowindows @ markers on 2 maps

分類Dev

Google maps clear all markers before placing new one

分類Dev

Google Maps API 3 Load Markers from MySQL from current position

分類Dev

Get Markers Addresses in Input fields using Drag-able Google Maps API V3

分類Dev

Map markers not rendering - Google Maps Javascript API v3 In Phonegap

分類Dev

Adding Multiple Markers in real time google maps v2 android

分類Dev

How to manage Markers well using google maps api v2 on android

分類Dev

Grouping and displaying values in ReactJs

分類Dev

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

分類Dev

displaying Google Maps API v2 on real device/emulator. can't figure out error

分類Dev

Why is only one Google Maps V2 marker displaying in a Fragment?

分類Dev

How to apply CSS to Here Maps API Markers

分類Dev

Draw circles around multiple markers in Maps

分類Dev

AngularJS Google Map with Multiple Markers

分類Dev

TypeError:google.maps.Markersはコンストラクターではありません

分類Dev

Add markers to Google Map when navigate the map

分類Dev

Animation of google markers on map load with timeout

Related 関連記事

  1. 1

    Google Maps jQuery Marker not Displaying

  2. 2

    Placing Circles instead of Markers in google maps

  3. 3

    Google maps delete all markers and then create new

  4. 4

    Google Maps: infobox turns up behind markers?

  5. 5

    Google Maps fit markers in custom bounds

  6. 6

    Google maps API markers content hide by default

  7. 7

    How to hide/show groups of markers by category with Google Maps in Android?

  8. 8

    Google Maps API 3 - Show All Markers on Screen, but Keep Centerpoint

  9. 9

    How to get all markers in google-maps-react

  10. 10

    How to Add Google Maps with Multiple Markers Showing Infowindows on Load and on Click

  11. 11

    How to delete markers from my own google maps

  12. 12

    Setting listeners to groups of markers using Google Maps API

  13. 13

    Google Map API V3 - infowindows @ markers on 2 maps

  14. 14

    Google maps clear all markers before placing new one

  15. 15

    Google Maps API 3 Load Markers from MySQL from current position

  16. 16

    Get Markers Addresses in Input fields using Drag-able Google Maps API V3

  17. 17

    Map markers not rendering - Google Maps Javascript API v3 In Phonegap

  18. 18

    Adding Multiple Markers in real time google maps v2 android

  19. 19

    How to manage Markers well using google maps api v2 on android

  20. 20

    Grouping and displaying values in ReactJs

  21. 21

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

  22. 22

    displaying Google Maps API v2 on real device/emulator. can't figure out error

  23. 23

    Why is only one Google Maps V2 marker displaying in a Fragment?

  24. 24

    How to apply CSS to Here Maps API Markers

  25. 25

    Draw circles around multiple markers in Maps

  26. 26

    AngularJS Google Map with Multiple Markers

  27. 27

    TypeError:google.maps.Markersはコンストラクターではありません

  28. 28

    Add markers to Google Map when navigate the map

  29. 29

    Animation of google markers on map load with timeout

ホットタグ

アーカイブ