ReactJS: Google Map Component
Steps to implement google maps in Facebook’s ReactJS Web Application
1. Add npm module in your project for react-google-maps
npm install --save react-google-maps # or yarn add react-google-maps
Reference : https://github.com/tomchentw/react-google-maps
Before this you have to include google maps api sdk in your index.ejs file
<script src=”https://maps.googleapis.com/maps/api/js?v=3.27&libraries=places,geometry&key=<YOUR_API_KEY>”></script>
How to get Google Maps Api Key ?
Follow the steps given in this link
2. Create Google Map Handler Component
'use strict'; import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import update from 'react-addons-update'; import canUseDOM from 'can-use-dom'; import raf from 'raf'; import GoogleMapComponent from './gMapComponent'; const geolocation = ( canUseDOM && navigator.geolocation ? navigator.geolocation : ({ getCurrentPosition(success, failure) { failure('Your browser doesnt support geolocation.'); }, }) ); class GoogleMapHandlerComponent extends React.Component { state = { bounds: null, center: null, content: null, radius: 400, markers: [] }; constructor(props) { super(props); if (props !== null && props !== undefined && props.location !== null && props.location !== undefined && props.location.markers !== null && props.location.markers !== undefined) { const locationInfo = { center: props.location.center, markers: props.location.markers }; this.state = locationInfo; } } componentDidMount() { const tick = () => { if (this.isUnmounted) { return; } this.setState({ radius: Math.max(this.state.radius - 5, 0) }); if (this.state.radius > 10) { raf(tick); } }; geolocation.getCurrentPosition((position) => { if (this.isUnmounted) { return; } this.setState({ center: { lat: position.coords.latitude, lng: position.coords.longitude, }, content: 'Location found using HTML5.', }); raf(tick); }, (reason) => { if (this.isUnmounted) { return; } this.setState({ center: { lat: 60, lng: 105, }, content: 'Error: The Geolocation service failed (${reason}).', }); }); if (document.getElementsByClassName('pac-container').length > 0) { const gmapSearchResultsBox = document.getElementsByClassName('pac-container')[0]; gmapSearchResultsBox.style.zIndex = '2000'; } } componentWillReceiveProps(nextProps) { if (nextProps !== null && nextProps !== undefined && nextProps.location !== null && nextProps.location !== undefined && nextProps.location.markers !== null && nextProps.location.markers !== undefined) { this.setState({ center: nextProps.location.center, markers: nextProps.location.markers }); } } componentDidUpdate() { if (document.getElementsByClassName('pac-container').length > 0) { const gmapSearchResultsBox = document.getElementsByClassName('pac-container')[0]; gmapSearchResultsBox.style.zIndex = '2000'; } } componentWillUnmount() { this.isUnmounted = true; } isUnmounted = false; handleMapMounted = this.handleMapMounted.bind(this); handleBoundsChanged = this.handleBoundsChanged.bind(this); handleSearchBoxMounted = this.handleSearchBoxMounted.bind(this); handlePlacesChanged = this.handlePlacesChanged.bind(this); handleMarkerClose = this.handleMarkerClose.bind(this); handleMarkerClick = this.handleMarkerClick.bind(this); handleMapMounted(map) { this._map = map; } handleBoundsChanged() { this.setState({ bounds: this._map.getBounds(), center: this._map.getCenter(), }); } handleSearchBoxMounted(searchBox) { this._searchBox = searchBox; } handleLoadPlaces(markers) { } handlePlacesChanged() { const places = this._searchBox.getPlaces(); // Add a marker for each place returned from search bar const markers = places.map(place => ({ position: place.geometry.location, })); // Set markers; set map center to first search result const mapCenter = markers.length > 0 ? markers[0].position : this.state.center; this.setState({ center: mapCenter, markers, }); this.props.handleLocationChange(mapCenter, places); } // Toggle to 'true' to show InfoWindow and re-renders component handleMarkerClick(targetMarker) { this.setState({ markers: this.state.markers.map(marker => { if (marker === targetMarker) { if (marker.showInfo) { return { ...marker, showInfo: false, }; } return { ...marker, showInfo: true, }; } return marker; }), }); } handleMarkerClose(targetMarker) { this.setState({ markers: this.state.markers.map(marker => { if (marker === targetMarker) { return { ...marker, showInfo: false, }; } return marker; }), }); } render() { return ( <GoogleMapComponent containerElement={ <div style={{ height: '100%' }} /> } mapElement={ <div style={{ height: '100%' }} /> } center={this.state.center} onMapMounted={this.handleMapMounted} onBoundsChanged={this.handleBoundsChanged} onSearchBoxMounted={this.handleSearchBoxMounted} bounds={this.state.bounds} onPlacesChanged={this.handlePlacesChanged} onMarkerClick={this.handleMarkerClick} onMarkerClose={this.handleMarkerClose} markers={this.state.markers} /> ); } } function mapDispatchToProps(dispatch) { return bindActionCreators({ }, dispatch); } export default connect(null, mapDispatchToProps)(GoogleMapHandlerComponent);
3. Create Google Map Component, this component uses the components of react-google-maps module
'use strict'; import React from 'react'; import IconButton from 'material-ui/IconButton'; import { withGoogleMap, GoogleMap, Circle, InfoWindow, Marker } from 'react-google-maps'; import SearchBox from 'react-google-maps/lib/places/SearchBox'; import GoogleMapMarkerInfoWindow from './gMapMarkerInfoWindow'; import layoutStyle from '../../../constants/layoutStyle'; const INPUT_STYLE = { boxSizing: 'border-box', MozBoxSizing: 'border-box', border: '1px solid transparent', width: '240px', height: '32px', marginTop: '27px', marginRight: '20px', padding: '0 12px', borderRadius: '1px', boxShadow: '0 2px 6px rgba(0, 0, 0, 0.3)', fontSize: '14px', outline: 'none', textOverflow: 'ellipses', }; const GoogleMapComponent = withGoogleMap(props => ( <GoogleMap ref={props.onMapMounted} defaultZoom={15} center={props.center} onBoundsChanged={props.onBoundsChanged} > <SearchBox ref={props.onSearchBoxMounted} bounds={props.bounds} controlPosition={google.maps.ControlPosition.TOP_RIGHT} onPlacesChanged={props.onPlacesChanged} inputPlaceholder='Search Location' inputStyle={INPUT_STYLE} /> {props.markers.map((marker, index) => ( <Marker key={index} position={marker.position} onClick={() => props.onMarkerClick(marker)} > {/* Show info window only if the 'showInfo' key of the marker is true. That is, when the Marker pin has been clicked and 'onCloseClick' has been Successfully fired. */} {marker.showInfo && (marker.pinOnly === null || marker.pinOnly === undefined || !marker.pinOnly) && ( <InfoWindow onCloseClick={() => props.onMarkerClose(marker)}> <GoogleMapMarkerInfoWindow infoContent={marker.infoContent} /> </InfoWindow> )} </Marker> ))} {props.center && ( <Circle center={props.center} radius={props.radius} options={{ fillColor: 'red', fillOpacity: 0.20, strokeColor: 'red', strokeOpacity: 1, strokeWeight: 1, }} /> )} </GoogleMap> )); export default GoogleMapComponent;
4. Use Google Map Handler component whereever you wish to place the map
render() { const handleLocationChange = this.handleLocationChange; const mapsComponent = ( <GoogleMapHandlerComponent location={this.props.location} handleLocationChange={handleLocationChange.bind(this)} />); return ( <div id='mapId' style={{ width: '450px', height: '350px' }} > {mapsComponent} </div> ); }
Note you have to pass your current location to land user on his current location, else any other location which is default location.
and a callback for handling change in location.
ReactJS google map location change callback will be called by react-google-maps library when there is change in location,
like user searched some location
Also check stateless react components : http://knowledge-cess.com/reactjs-functional-or-stateless-components/