Fra*_*nva 4 google-maps-api-3 google-places-api reactjs gatsby
我正在尝试使用Google Place API的自动完成地址服务。
找到了这个库:https : //github.com/kenny-hibino/react-places-autocomplete#load-google-library
它要求在我的项目中加载库:https : //github.com/kenny-hibino/react-places-autocomplete#getting-started
如果它是纯Reactjs项目,我会在public / index.html中进行。但是,每次运行时,Gatsbyjs项目中的public / index.html都会被删除并重新生成:
Gatsby develop
Run Code Online (Sandbox Code Playgroud)
命令行。
如何在Gatsbyjs项目中使用Google Place API?
我尝试了两种方法来实现这一目标。
在/layouts/index.js中使用React-Helmet,如下所示:
<Helmet>
<script src="https://maps.googleapis.com/maps/api/js?key={API}&libraries=places&callback=initAutocomplete" async defer></script>
</Helmet>
Run Code Online (Sandbox Code Playgroud)
将脚本引用放在/public/index.html中,如下所示:
<!DOCTYPE html>
<html>
<head>
<meta charSet="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<title data-react-helmet="true"></title>
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key={API_KEY}&libraries=places" async defer ></script>
</head>
<body>
<div id="___gatsby"></div>
<script src="/commons.js"></script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)对于第一种解决方案,每次刷新页面后,项目都会引发错误,要求加载Google JavaScript Map API。
对于第二种解决方案,每次我通过命令行重新启动Gatsby之后: gatsby develop
它重新生成index.html,刷新掉其中的JavaScript参考。
这是一个更现代的实现,它使用 React 钩子和一些基于React.memo自定义shouldUpdate函数的性能优化。有关详细信息,请参阅此博客文章。
import { functions, isEqual, omit } from 'lodash'
import React, { useState, useEffect, useRef } from 'react'
function Map({ options, onMount, className, onMountProps }) {
const ref = useRef()
const [map, setMap] = useState()
useEffect(() => {
// The Map constructor modifies its options object in place by adding
// a mapTypeId with default value 'roadmap'. This confuses shouldNotUpdate.
// { ...options } prevents this by passing in a copy.
const onLoad = () =>
setMap(new window.google.maps.Map(ref.current, { ...options }))
if (!window.google) {
const script = document.createElement(`script`)
script.src = `https://maps.googleapis.com/maps/api/js?key=` + YOUR_API_KEY
document.head.append(script)
script.addEventListener(`load`, onLoad)
return () => script.removeEventListener(`load`, onLoad)
} else onLoad()
}, [options])
if (map && typeof onMount === `function`) onMount(map, onMountProps)
return (
<div
style={{ height: `60vh`, margin: ` 1em 0`, borderRadius: ` 0.5em` }}
{...{ ref, className }}
/>
)
}
function shouldNotUpdate(props, nextProps) {
const [funcs, nextFuncs] = [functions(props), functions(nextProps)]
const noPropChange = isEqual(omit(props, funcs), omit(nextProps, nextFuncs))
const noFuncChange =
funcs.length === nextFuncs.length &&
funcs.every(fn => props[fn].toString() === nextProps[fn].toString())
return noPropChange && noFuncChange
}
export default React.memo(Map, shouldNotUpdate)
Map.defaultProps = {
options: {
center: { lat: 48, lng: 8 },
zoom: 5,
},
}
Run Code Online (Sandbox Code Playgroud)
src/html.js像这样修改(如 Nenu 建议的那样)是一种选择。
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class HTML extends Component {
render() {
return (
<html {...this.props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{this.props.headComponents}
</head>
<body {...this.props.bodyAttributes}>
{this.props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: this.props.body }}
/>
{this.props.postBodyComponents}
// MODIFICATION // ===================
<script
src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"
async
defer
/>
// ===================
</body>
</html>
)
}
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以从项目中的任何位置访问 Google Maps API window.google.maps.(Map|Marker|etc.)。
不过,对我来说,这感觉有点不合时宜。如果你想要一个可重用的 React 组件,你可以将它作为 导入到任何页面或模板中import Map from './Map',我建议这样做。(提示:有关等效功能组件,请参阅下面的更新。)
// src/components/Map.js
import React, { Component } from 'react'
export default class Map extends Component {
onLoad = () => {
const map = new window.google.maps.Map(
document.getElementById(this.props.id),
this.props.options
)
this.props.onMount(map)
}
componentDidMount() {
if (!window.google) {
const script = document.createElement('script')
script.type = 'text/javascript'
script.src = `https://maps.google.com/maps/api/js?key=YOUR_API_KEY`
const headScript = document.getElementsByTagName('script')[0]
headScript.parentNode.insertBefore(script, headScript)
script.addEventListener('load', () => {
this.onLoad()
})
} else {
this.onLoad()
}
}
render() {
return <div style={{ height: `50vh` }} id={this.props.id} />
}
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
// src/pages/contact.js
import React from 'react'
import Map from '../components/Map'
const center = { lat: 50, lng: 10 }
const mapProps = {
options: {
center,
zoom: 8,
},
onMount: map => {
new window.google.maps.Marker({
position: center,
map,
title: 'Europe',
})
},
}
export default function Contact() {
return (
<>
<h1>Contact</h1>
<Map id="contactMap" {...mapProps} />
</>
)
}
Run Code Online (Sandbox Code Playgroud)
您不应该public使用GatsbyJS修改forlder中的任何文件。
相反,我建议您自定义html.js文件。
为此,首先运行:
cp .cache/default-html.js src/html.js
Run Code Online (Sandbox Code Playgroud)
您应该html.js在/src/html.js中拥有该文件。
现在,您可以将<script>标记放入中<head>。
| 归档时间: |
|
| 查看次数: |
1493 次 |
| 最近记录: |