Hi there,
I need to use Google Auto Complete API on my address search textbox.
I found this library:
https://github.com/kenny-hibino/react-places-autocomplete
Which asks for loading this script
into my project.
What I have tried?
gatsby develop<!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>
I included this script in-between
<Helmet>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key={API}&libraries=places&callback=initAutocomplete" async defer></script>
</Helmet>
this sometime works, but when I refresh my page, it breaks and asks for loading the Google Map API lib.
Been stuck here for a day~!
Please help.
This could be documented better I think, but you can use the onRenderBody API to do this. Have a look at this example.
Oh and here's a link to the onRenderBody docs
You could also try customizing html.js.
Is using onRenderBody a better approach?
It's cleaner as the code can be put into a plugin. But either way works and for a one-off integration, editing html.js is often easier.
thanks guys, since I am not using Server Side Rendering, so the onRenderBody() doesn't fit for me.
I ended up using html.js and it works well :)
Thanks you all for your help, love Gatsbyjs ~~!!!
I'm trying to do something similar with the Maps JavaScript API but I'm confused as to where the Google code is supposed to go inside of html.js. I've tried before the closing </body> and also inside the <head> of html.js. In both cases, while I don't get any errors, I don't see any map either 馃槙
I figured it out... I needed to use dangerouslySetInnerHTML:
<script dangerouslySetInnerHTML={{
__html: `
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
});
}
`,
}} />
_However_, I'm still struggling to figure out how to have the map stay when navigating to a new page and back again. Map seems to load only on page reloads.
In case someone (like me) stumbles upon this looking for a way to implement a Google Maps component in Gatsby, here are two ways to do it.
Modifying src/html.js like so (as suggested above) is one option.
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,
}
Then you can access the Google Maps API anywhere in your project from window.google.maps.[Map/Marker/etc.].
To me that felt a little anachronistic, though. If you want a reusable React component that you can import into any page or template as import Map from './Map', I suggest this instead.
// 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} />
}
}
Use it like so:
// 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',
})
},
}
const Contact = () => {
return (
<h1>Contact</h1>
<Map id="contactMap" {...mapProps} />
)
}
export default Contact
Most helpful comment
In case someone (like me) stumbles upon this looking for a way to implement a Google Maps component in Gatsby, here are two ways to do it.
Using html.js
Modifying
src/html.jslike so (as suggested above) is one option.Then you can access the Google Maps API anywhere in your project from
window.google.maps.[Map/Marker/etc.].The React way
To me that felt a little anachronistic, though. If you want a reusable React component that you can import into any page or template as
import Map from './Map', I suggest this instead.Use it like so: