This tutorial aims at integrating the google maps API to your React components and enabling you to display maps on your website.
本教程旨在将google maps API集成到您的React组件中,并使您能够在网站上显示地图。
Google Maps API简介。 (Introduction to Google Maps API.)
At some point of our lives, we've all gotten a chance to use and interact with the google maps, either through finding directions, viewing our current location, ordering cabs or estimating distance and time from one point to another.
在我们生活的某个时刻,我们所有人都有机会使用Google地图并与之互动,方法是查找方向,查看我们的当前位置,订购出租车或估算从一点到另一点的距离和时间。
Including the Google maps API in a React App is actually far much easier than expected due to its rich documentation which I highly suggest that you look into, and the npm package by Fullstack React.
实际上,由于其丰富的文档 (我强烈建议您研究一下)以及Fullstack React的npm软件包 ,因此在React App中包括Google Maps API实际上比预期的要容易得多。
先决条件: ( Prerequisite: )
- React Knowledge (at least intermediate level) React知识(至少中级水平)
- A Google Maps API Key Google Maps API密钥
Go on ahead and grab your API key here.
- Simply click on the Get Started button 只需单击“入门”按钮
- Tick on the maps checkbox 勾选地图复选框
- Click Create A New Project 单击创建一个新项目
- Once you’ve named your project (whatever you want) you can set up your billing info which will automatically enable your the API and generate the API key. 为项目命名后(无论您要使用什么名称),您都可以设置结算信息,这将自动启用您的API并生成API密钥。
PS: Do not be hesitant of adding your billing info as the Google cloud platform offers you a 12-month free trial period and will not bill you after the trial period until you give your permission.
PS:不要犹豫,添加您的帐单信息,因为Google云平台为您提供12个月的免费试用期,并且在您允许之前不会向您收费。
项目设置 ( Project Setup )
For some quick setup, we are going to use facebook's create-react-app which saves us the hassle of having to configure webpack or babel.
为了进行一些快速设置,我们将使用Facebook的create-react-app ,这免除了我们配置webpack或babel的麻烦。
So go on ahead and run this command
因此,继续执行此命令
npm i -g create-react-app
create-react-app my-googlemap
cd my-googlemap
Before we add any code, let’s go ahead and install our dependency.
在添加任何代码之前,让我们继续安装我们的依赖项。
npm install --save google-maps-react
Let's go on and edit our src
folder and remove files and imports that we do not need ie
让我们继续编辑我们的src
文件夹,并删除我们不需要的文件和导入,即
logo.svg
logo.svg
App.css
App.css
index.css
index.css
- In
index.js
remove the css import. 在index.js
删除css导入。
是时候创建我们的组件了。 (Time to create our component.)
We will need to edit our App.js
file and instead have our component that will load our google map.
我们将需要编辑App.js
文件,而要使用我们的组件来加载Google地图。
import React, { Component } from 'react';
import { Map, GoogleApiWrapper } from 'google-maps-react';
const mapStyles = {
width: '100%',
height: '100%'
};
export class MapContainer extends Component {
render() {
return (
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
initialCenter={{
lat: -1.2884,
lng: 36.8233
}}
/>
);
}
}
export default GoogleApiWrapper({
apiKey: 'YOUR_GOOGLE_API_KEY_GOES_HERE'
})(MapContainer);
For a simple Google Map, this is literally all the code you need. Go ahead and run your app and ensure that the map loads to the browser.
对于简单的Google Map,这实际上就是您需要的所有代码。 继续并运行您的应用程序,并确保将地图加载到浏览器。
The Map component takes in some optional props such as style(the CSS style object), Zoom(number value representing a tighter focus on the map's center) and initialCenter(an object containing latitude and longitude coordinates)
Map组件带有一些可选的道具,例如style(CSS样式对象),Zoom(表示在地图中心的焦点的数字值)和initialCenter(包含纬度和经度坐标的对象)
The GoogleApiWrapper
is simply a Higher Order Component(HOC) that provides wrapper around Google APIs. Alternatively, the GoogleApiWrapper HOC can be configured by passing a function that will be called with the wrapped component's props and should return the configuration object like so.
GoogleApiWrapper
只是一个高阶组件(HOC) ,它提供了围绕Google API的包装器。 或者,可以通过传递一个函数来配置GoogleApiWrapper HOC,该函数将使用包装的组件的props调用,并且应该像这样返回配置对象。
export default GoogleApiWrapper(
(props) => ({
apiKey: props.apiKey
}
))(MapContainer)
标记和infoWindow ( Markers and infoWindow )
Wouldn't it be exciting to have a Marker and an infoWindow on our map showing our set initialCenter position? So let's add this functionality to our code.
在我们的地图上显示我们设置的initialCenter位置的Marker和infoWindow会不会令人兴奋? 因此,让我们将此功能添加到我们的代码中。
First we need to import Marker
and infoWindow
components from the google-maps-react library inorder to help us achieve loading of the two.
首先,我们需要从google-maps-react库导入Marker
和infoWindow
组件,以帮助我们实现两者的加载。
import { GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';
Notice that our component before was stateless?, We need to add state for state management.
注意,我们之前的组件是无状态的吗?,我们需要为状态管理添加状态。
[...]
export class MapContainer extends Component {
state = {
showingInfoWindow: false, //Hides or the shows the infoWindow
activeMarker: {}, //Shows the active marker upon click
selectedPlace: {} //Shows the infoWindow to the selected place upon a marker
};
Next, we need to add event handlers for when the map and the marker are clicked.
接下来,我们需要为单击地图和标记的时间添加事件处理程序。
onMarkerClick = (props, marker, e) =>
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
onClose = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
- The
onMarkerClick
is used to show the InfoWindow which is a component in the google-maps-react library which gives us the ability for a pop-up window showing details of the clicked place/marker.onMarkerClick
用于显示InfoWindow,它是google-maps-react库中的一个组件,它使我们能够使用弹出窗口来显示单击的位置/标记的详细信息。
Sidenote: the visibility of the infoWindow is controlled by the boolean visible prop which shows the InfoWindow component when true and hides it when false.
旁注:infoWindow的可见性由布尔可见道具控制,该道具在true时显示InfoWindow组件,在false时隐藏它。
- The
onClose
basically is for closing the InfoWindow once a user clicks on the close button on the infoWindow.onClose
基本上用于在用户单击infoWindow上的关闭按钮后关闭InfoWindow。
Let's complete our component by adding our Marker and InfoWindow components to our render method
让我们通过将Marker和InfoWindow组件添加到render方法来完善我们的组件
render() {
return (
<Map
google={this.props.google}
zoom={14}
style={style}
initialCenter={{ lat: -1.2884, lng: 36.8233 }
>
<Marker
onClick={this.onMarkerClick}
name={'Kenyatta International Convention Centre'}
/>
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
onClose={this.onClose}
>
<div>
<h4>{this.state.selectedPlace.name}</h4>
</div>
</InfoWindow>
</Map>
);
}
}
[...]
Run your app and ensure you have the one marker with the infoWindow upon click.
运行您的应用程序,并确保单击时有一个带有InfoWindow的标记。
- TODO: Try and add a few more markers on your map and more interactivity to your infoWindow. 待办事项:尝试在地图上添加更多标记,并增加与infoWindow的交互性。
浏览器的当前位置 ( Browser's current location )
Let's spice things up by having our map pick our browser's current location. We will be using navigator which is a read-only property that returns a Geolocation object that gives Web content access to the location of the device.
让我们为地图选择浏览器的当前位置,为事情增添趣味。 我们将使用导航器 ,它是一个只读属性,它返回Geolocation对象,该对象使Web内容可以访问设备的位置。
In our src
folder create a new file and name it Map.js
and create a component named CurrentLocation
this is where all our functionality to pick our browser's location will lie.
在我们的src
文件夹中,创建一个新文件并将其命名为Map.js
并创建一个名为CurrentLocation
的组件,这是我们选择浏览器位置的所有功能所在。
We will begin by adding some default props to our CurrentLocation
component, since we will need to set the map with a center incase the current location is not provided.This is handled by the boolean prop centerAroundCurrentLocation
我们将首先在CurrentLocation
组件中添加一些默认道具,因为在未提供当前位置的情况下,我们需要将地图设置为中心,这由布尔道具centerAroundCurrentLocation
处理
import React from 'react';
import ReactDOM from 'react-dom';
const mapStyles = {
map: {
position: 'absolute',
width: '100%',
height: '100%'
}
};
export class CurrentLocation extends React.Component {
[...]
}
export default CurrentLocation;
CurrentLocation.defaultProps = {
zoom: 14,
initialCenter: {
lat: -1.2884,
lng: 36.8233
},
centerAroundCurrentLocation: false,
visible: true
};
Next, we need to make our component stateful,
接下来,我们需要使组件有状态,
[...]
export class CurrentLocation extends React.Component {
constructor(props) {
super(props);
const { lat, lng } = this.props.initialCenter;
this.state = {
currentLocation: {
lat: lat,
lng: lng
}
};
}
[...]
}
Let's also update our CurrentLocation component to cater for the instance when the Map is first loaded as we cannot solely depend upon the google API being always available, hence we need to check if it's loaded. And also check if the browser's current location is provided and recenter the map to it.
我们还要更新我们的CurrentLocation组件,以适应首次加载地图时的实例,因为我们不能仅依赖于始终可用的google API,因此我们需要检查它是否已加载。 还要检查是否提供了浏览器的当前位置,并将地图更新到该位置。
[...]
componentDidUpdate(prevProps, prevState) {
if (prevProps.google !== this.props.google) {
this.loadMap();
}
if (prevState.currentLocation !== this.state.currentLocation) {
this.recenterMap();
}
}
[...]
Let's define the recenterMap()
function which only gets called when the currentLocation in the component's state is updated and uses the .panTo()
method on the google.maps.Map instance to change the center of the map.
让我们定义一个recenterMap()
函数,该函数仅在组件状态下的currentLocation更新时才调用,并使用google.maps.Map实例上的.panTo()
方法更改地图的中心。
[...]
recenterMap() {
const map = this.map;
const current = this.state.currentLocation;
const google = this.props.google;
const maps = google.maps;
if (map) {
let center = new maps.LatLng(current.lat, current.lng);
map.panTo(center);
}
}
[...]
Next, we need to handle the instance when the map has already loaded.This will be handled by the componentDidMount()
Lifecycle method which will set a call back to fetch the current location.
接下来,我们需要在地图已经加载时处理实例,这将由componentDidMount()
Lifecycle方法处理,该方法将设置回叫以获取当前位置。
[...]
componentDidMount() {
if (this.props.centerAroundCurrentLocation) {
if (navigator && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(pos => {
const coords = pos.coords;
this.setState({
currentLocation: {
lat: coords.latitude,
lng: coords.longitude
}
});
});
}
}
this.loadMap();
}
[...]
Notice the loadMap()
function? Let's go on ahead and define it.
注意loadMap()
函数吗? 让我们继续定义它。
[...]
loadMap() {
if (this.props && this.props.google) {
// checks if google is available
const { google } = this.props;
const maps = google.maps;
const mapRef = this.refs.map;
// reference to the actual DOM element
const node = ReactDOM.findDOMNode(mapRef);
let { zoom } = this.props;
const { lat, lng } = this.state.currentLocation;
const center = new maps.LatLng(lat, lng);
const mapConfig = Object.assign(
{},
{
center: center,
zoom: zoom
}
);
// maps.Map() is constructor that instantiates the map
this.map = new maps.Map(node, mapConfig);
}
}
Basically, the loadMap()
function is only called after the component has been rendered and grabs a reference to the DOM component to where we want our map to be placed.
基本上,仅在呈现组件之后才调用loadMap()
函数,并获取对DOM组件的引用,该引用指向我们要放置地图的位置。
Our CurrentLocation component is almost looking up, But we need to ensure that our previous Marker picks our currenct location ie the browsers current location and so we need to introduce Parent-Child concept through the renderChildren()
method which will be responsible for actually calling the method on the child component.
我们的CurrentLocation组件几乎要查找,但是我们需要确保之前的标记选择了当前位置,即浏览器的当前位置,因此我们需要通过renderChildren()
方法引入Parent-Child概念,该方法将负责实际调用子组件上的方法。
Read more about Parent-Child communication here
[...]
renderChildren() {
const { children } = this.props;
if (!children) return;
return React.Children.map(children, c => {
if (!c) return;
return React.cloneElement(c, {
map: this.map,
google: this.props.google,
mapCenter: this.state.currentLocation
});
});
}
[...]
And finally, let's add our render()
method
最后,让我们添加render()
方法
[...]
render() {
const style = Object.assign({}, mapStyles.map);
return (
<div>
<div style={style} ref="map">
Loading map...
</div>
{this.renderChildren()}
</div>
);
}
[...]
Lastly, before we wind up we need to update our MapContainer
component to include our new changes. So let's change it to this
最后,在结束之前,我们需要更新MapContainer
组件以包括我们的新更改。 所以我们将其更改为
import React, { Component } from 'react';
import { GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';
import CurrentLocation from './Map';
export class MapContainer extends Component {
state = {
showingInfoWindow: false,
activeMarker: {},
selectedPlace: {}
};
onMarkerClick = (props, marker, e) =>
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
onClose = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
render() {
return (
<CurrentLocation
centerAroundCurrentLocation
google={this.props.google}
>
<Marker onClick={this.onMarkerClick} name={'current location'} />
<InfoWindow
marker={this.state.activeMarker}
visible={this.state.showingInfoWindow}
onClose={this.onClose}
>
<div>
<h4>{this.state.selectedPlace.name}</h4>
</div>
</InfoWindow>
</CurrentLocation>
);
}
}
export default GoogleApiWrapper({
apiKey: 'YOUR_GOOGLE_API_KEY_GOES_HERE'
})(MapContainer);
Run your app; heading over to our browser, our map should first load with our initialCenter
then reload to pick our browser's current location with the marker positioned to this location and Voilà we are done.
运行您的应用; 转到浏览器,我们的地图应首先加载我们的initialCenter
然后重新加载以选择浏览器的当前位置,并将标记定位到该位置,然后完成操作。
结论 ( Conclusion )
In this article we've been able to load our google maps React component, add a marker and have an infoWindow onto it and also have the map pick our current location. While we did not dive into adding more functionalities to our map such as, having polylines and polygons or adding event listeners, I highly recommend that you look into them
在本文中,我们已经能够加载Google Maps React组件,添加标记并在其上添加一个infoWindow,还可以让地图选择我们的当前位置。 虽然我们并未考虑向地图添加更多功能,例如具有折线和多边形或添加事件侦听器,但我强烈建议您调查一下它们
翻译自: https://scotch.io/tutorials/react-apps-with-the-google-maps-api-and-google-maps-react