如何将GoogleMapsAPI集成到React应用程序中
介绍
Google Maps 是 Google 提供的地图服务,支持多种配置设置。 将 Google 地图添加到您的应用程序可以为用户提供比街道地址或一组坐标更多的上下文信息。
本教程旨在将 Google Maps API 集成到您的 React 组件中,并使您能够在您的网站上显示地图。
先决条件
要完成本教程,您需要:
- Node.js 安装在本地,您可以按照【X57X】如何安装Node.js 并创建本地开发环境【X126X】进行。
- 熟悉 React JavaScript 框架。
- Google Maps JavaScript API 密钥。 这将需要一个 Google 帐户,登录到 Google Cloud Platform Console,创建一个新项目,并为该项目启用 Google Maps JavaScript API。
注意: 为避免在使用 Google Maps API 时出现“仅用于开发目的”消息,您需要提供有效的信用卡并将其与 Google Cloud 项目的结算帐户相关联,但它是本教程不需要。
本教程已使用 Node v14.2.0、npm v6.14.5、react v16.13.1 和 google-maps-react v.2.0.6 进行了验证。
第 1 步 - 设置 React 应用程序
在本教程中,您将使用 create-react-app 来搭建一个新的 React 应用程序。
首先,运行 npx 以在终端窗口中使用 create-react-app:
npx create-react-app react-googlemaps
然后,导航到您的新项目目录:
cd react-googlemaps
在添加任何代码之前,让我们安装您的依赖项:
npm install google-maps-react@2.0.6
注意: 可选地,此时您可以删除 src 目录中不必要的文件和导入。 您不需要 logo.svg、App.css、index.css。 如果删除 index.css,还应删除 index.html 中 index.css 的 import 以避免构建错误。
此时,您有了一个带有 google-maps-react 库的 React 应用程序。 您现在可以在应用程序中使用地图进行探索。
第 2 步 — 使用 Map 和 GoogleApiWrapper
接下来,您将需要编辑 App.js 文件并将代码替换为将加载 Google 地图的组件。
打开App.js:
nano src/App.js
将 App.js 的内容替换为以下代码行:
src/App.js
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_MAPS_API_KEY_GOES_HERE'
})(MapContainer);
注意: 将 YOUR_GOOGLE_MAPS_API_KEY_GOES_HERE 替换为您的 Google Maps JavaScript API 密钥。
警告: 请务必避免将您的 API 密钥保存在您提交到公共存储库(如 GitHub)的任何文件中,因为它可能会被其他人用于您不打算的目的。
对于基本 Google 地图的功能,这就是您需要的所有代码。
Map 组件接受一些可选的道具:
style- CSS 样式对象zoom- 数字值表示更紧密地关注地图的中心initialCenter- 包含经纬度坐标的对象
在此示例中,您定义:
- 具有
100%宽度和100%高度的 CSS 样式对象 14的缩放值- 地点
-1.2884, 36.8233(肯尼亚内罗毕的肯雅塔国际会议中心)
打开您的终端并运行您的应用程序:
npm start
并确保地图加载到浏览器:
GoogleApiWrapper 是一个 高阶组件 (HOC),它提供了 Google API 的包装器。 或者,可以通过传递一个函数来配置 GoogleApiWrapper HOC,该函数将使用包装组件的 props 调用,并且应该返回配置对象,如下所示:
export default GoogleApiWrapper(
(props) => ({
apiKey: props.apiKey
}
))(MapContainer)
此时,您的 React 应用程序中有一个 Google 地图。 您现在可以探索实现 Google 地图的其他功能。
第 3 步 — 使用 Markers 和 InfoWindow
您现在将在代码中添加一个 Marker 和一个 InfoWindow。
首先,您需要从 google-maps-react 库中导入 Marker 和 InfoWindow 组件,以帮助您实现两者的加载。
src/App.js
import React, { Component } from 'react';
import { Map, GoogleApiWrapper, InfoWindow, Marker } from 'google-maps-react';
注意到您之前的组件是无状态的吗? 您将需要为状态管理添加状态。
src/App.js
// ...
export class MapContainer extends Component {
state = {
showingInfoWindow: false, // Hides or shows the InfoWindow
activeMarker: {}, // Shows the active marker upon click
selectedPlace: {} // Shows the InfoWindow to the selected place upon a marker
};
// ...
}
接下来,您需要为单击 Map 和 Marker 时添加事件处理程序。
src/App.js
// ...
export class MapContainer extends Component {
// ...
onMarkerClick = (props, marker, e) =>
this.setState({
selectedPlace: props,
activeMarker: marker,
showingInfoWindow: true
});
onClose = props => {
if (this.state.showingInfoWindow) {
this.setState({
showingInfoWindow: false,
activeMarker: null
});
}
};
// ...
}
onMarkerClick 方法用于显示 InfoWindow,它是 google-maps-react 库中的一个组件,它使您能够弹出窗口显示单击的 [ X176X]。
onClose 方法用于在用户单击 InfoWindow 上的关闭按钮后关闭 InfoWindow。
让我们通过将 <Marker> 和 <InfoWindow> 组件添加到 render 方法来完成您的组件:
src/App.js
// ...
export class MapContainer extends Component {
// ...
render() {
return (
<Map
google={this.props.google}
zoom={14}
style={mapStyles}
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>
);
}
}
运行您的应用程序:
npm start
并确保您在单击时拥有带有 InfoWindow 的 Marker:
作为后续练习,您可以在 <Map> 上添加更多 <Marker>,并为 <InfoWindow> 添加更多交互性。
第 4 步 — 显示用户的当前位置
您现在将设置地图以检索浏览器的当前位置。 您将使用 Navigator,它是一个只读属性,它返回一个 Geolocation 对象,该对象允许 Web 内容访问设备的位置。
在您的 src 目录中创建一个新文件并将其命名为 Map.js:
nano src/Map.js
您将创建一个名为 CurrentLocation 的组件——在这里您将构建所有功能以检索浏览器的位置:
src/Map.js
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> 组件添加一些默认道具,因为如果未提供当前位置,您将需要使用 center 设置地图。 这由布尔属性 centerAroundCurrentLocation 处理:
src/Map.js
// ...
CurrentLocation.defaultProps = {
zoom: 14,
initialCenter: {
lat: -1.2884,
lng: 36.8233
},
centerAroundCurrentLocation: false,
visible: true
};
接下来,您需要使您的组件有状态:
src/Map.js
// ...
export class CurrentLocation extends React.Component {
constructor(props) {
super(props);
const { lat, lng } = this.props.initialCenter;
this.state = {
currentLocation: {
lat: lat,
lng: lng
}
};
}
}
// ...
让我们也更新您的 <CurrentLocation> 组件,以处理由于网络问题或意外维护导致 Google Maps API 不可用的情况。 还可以处理提供浏览器当前位置并将地图重新定位到该位置的情况。
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
componentDidUpdate(prevProps, prevState) {
if (prevProps.google !== this.props.google) {
this.loadMap();
}
if (prevState.currentLocation !== this.state.currentLocation) {
this.recenterMap();
}
}
}
// ...
让我们定义当组件状态中的 currentLocation 更新时调用的 recenterMap() 函数。 它将使用 panTo() 方法来改变地图的中心。
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
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);
}
}
}
// ...
接下来,您将需要在地图已经加载时处理该场景。 这将由 componentDidMount() 生命周期方法处理,该方法将设置回调以获取当前位置。
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
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();
}
}
// ...
注意到 loadMap() 功能了吗? 让我们继续定义它。
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
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);
}
}
}
// ...
loadMap() 函数在组件被渲染后调用,并获取对 DOM 组件的引用,指向您希望放置地图的位置。
您的 <CurrentLocation> 组件几乎完成了。 但是你需要保证你之前的<Marker>选择的是你当前的位置(即浏览器的当前位置),所以需要通过renderChildren()引入Parent-Child组件通信 ] 方法,它将负责调用子组件上的方法。
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
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
});
});
}
}
// ...
最后,让我们添加您的 render() 方法:
src/Map.js
// ...
export class CurrentLocation extends React.Component {
// ...
render() {
const style = Object.assign({}, mapStyles.map);
return (
<div>
<div style={style} ref="map">
Loading map...
</div>
{this.renderChildren()}
</div>
);
}
}
// ...
最后,您需要在 App.js 中更新 MapContainer 组件:
nano src/App.js
用新的 CurrentLocation 组件替换 Map 组件:
src/App.js
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_MAPS_API_KEY_GOES_HERE'
})(MapContainer);
运行您的应用程序:
npm start
转到您的浏览器,您的地图应该首先加载您的 initialCenter 然后重新加载以选择浏览器的当前位置,并将 Marker 定位到该位置,瞧,您完成了:
结论
在本文中,您能够加载 <Map> React 组件,添加 Marker,并将 InfoWindow 关联到它。 您还使地图显示了您当前的位置。
基于这些知识,您可以实现更高级的功能,例如具有折线和多边形或将事件侦听器添加到地图中。
如果您想了解有关 React 的更多信息,请查看我们的 如何在 React.js 中编码,或查看 我们的 React 主题页面 以了解练习和编程项目。