Source: components/marker.js

import React from 'react';
import PropTypes from 'prop-types';

/**
* The component designed to implement the google.maps.Marker from the javascript api. <Marker /> components live within the context of any <Map /> component.
* @memberof Map
* @property {object} state
* @property {google.maps.Marker} state.Marker
* @property {object} props
* @property {google.maps.Map} props.map
* @property {google.maps} props.maps
* @property {object} props.coords Defines the coordinate pair where this marker should exits.
* @property {number} props.coords.lng Number defining longitude.
* @property {number} props.coords.lat Number defining latitude.
* @property {string|Icon} props.icon
* @property {google.maps.MarkerOptions} props.options See [Marker Options Documentation]{@link https://developers.google.com/maps/documentation/javascript/3.exp/reference#MarkerOptions}
*/
class Marker extends React.Component {
    constructor(props) {
        super(props);
        this.displayName = 'Marker';
        this.state = {
        	marker : null
        }

        this.getOptions = this.getOptions.bind(this);
    }
    componentWillMount() {
    	if(this.props.map && this.props.maps) {
    		var {map,maps, MarkerClusterer} = this.props;

    		var marker = new maps.Marker(this.getOptions());

    		marker.setMap(this.props.map);
        const {opacity} = this.props;
        if(opacity != null && !isNaN(Number(opacity))) {
          marker.setOpacity(this.props.opacity);
        }

    		this.setState({marker});

    		if(MarkerClusterer) {
          MarkerClusterer.addMarker(marker);
        }

    		if(typeof this.props.onClick === 'function')
	    		this.props.maps.event.addListener(marker, 'click', e => {
	    			if(this.props.onClick)
	    				this.props.onClick({coords : marker.getPosition().toJSON()})
	    		});
        if(typeof this.props.onDragEnd === 'function')
          this.props.maps.event.addListener(marker, 'dragend', e=> {
            this.props.onDragEnd(e.latLng.toJSON(), e);
          })
    	}
    	else {
    		// Whoah boy! We need a map bigly.
    		console.error(new Error("<Marker /> components must be instantiated within a Map component. Please check your component's context."))
    	}
    }
    componentWillUpdate() {

    }
    getOptions() {
		var options = {
			position : this.props.coords,
			// map : this.props.map,
			icon : this.props.icon ? this.props.icon : undefined
		}
		if(this.props.options)
			options = Object.assign(options, this.props.options);
    	return options;
    }
    componentWillUnmount() {
		if(this.state.marker) {
			this.state.marker.setMap(null);
		}
		this.setState({marker : null});

    }
    componentDidUpdate(prevProps, prevState) {
    	if(this.state.marker) {
    		this.state.marker.setOptions(this.getOptions())

            if(this.props.MarkerClusterer)
                this.props.MarkerClusterer.addMarker(this.state.marker);
    	}
    }
    render() {
    	var children = [];
    	if(this.props.children)
    		children = React.Children.map(this.props.children, child => React.cloneElement(child, {
    			map : this.props.map,
    			maps : this.props.maps,
    			anchor : this.state.marker
    		}));
        return <div>{children}</div>;
    }
}

Marker.propTypes = {
	maps : PropTypes.object,
	map : PropTypes.object,
	MarkerClusterer : PropTypes.object,
	options : PropTypes.object,
	anchor : PropTypes.object,
	coords : PropTypes.shape({
		lng : PropTypes.number,
		lat : PropTypes.number
	})
}

export default Marker;