title: How to implement Google Maps JS API in React without an external library?
body: <p>I'm trying to wrap my head around implementing external APIs in React, and want to be able to use Google Maps' API to display a map in a child component. Ideally, I want to understand how to do this without any external libraries to get a fundamental understanding of the process before using something like Axios. </p>
  
  <p>My question is this: how do I use the following snippet from the Google documentation for the API within React? </p>
  
  <pre><code>&lt;script async defer
        src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDZfVO29Iytspv4xz7S68doIoiztiRLhbk&amp;callback=initMap'&gt;
  &lt;/script&gt;
  </code></pre>
  
  <p>I tried using it within my index.html file but when I make a reference to the google object in a child component in React, I get an error:</p>
  
  <blockquote>
    <p>./src/Main.js   Line 114:  'google' is not defined  no-undef</p>
  </blockquote>
  
  <p>Even if it's not the preferred or most elegant way to do it, some basic understanding on how to implement the API without any external library would be greatly appreciated. Thank you!</p>
  
  <p>EDIT:</p>
  
  <p>My App.js:</p>
  
  <pre><code>import React, { Component } from 'react';
  import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
  import Main from './Main';
  
  import logo from './logo.svg';
  import './App.css';
  import injectTapEventPlugin from 'react-tap-event-plugin';
  
  injectTapEventPlugin();
  
  class App extends Component {
    render() {
      return (
        &lt;MuiThemeProvider&gt;
          &lt;Main /&gt;
        &lt;/MuiThemeProvider&gt;
      );
    }
  }
  
  export default App;
  </code></pre>
  
  <p>My Main.js: </p>
  
  <pre><code>import React, { Component } from 'react';
  import { FlatButton, Dialog, Card, Drawer, Paper, AppBar, Popover, Menu, MenuItem } from 'material-ui';
  
  var items = [
      {
          id: 0,
          name: 'Test 1',
          city: 'Toronto',
          longitude: 24.42142422,
          latitude: 49.24121415,
          tags: ['vegan', 'cheap', 'low-calorie'],
          reviews: [
              {
                  rating: 5,
                  reviewText: 'This was an amazing restaurant. Incredibly fast service, a large variety of options, and delicious food. I\'ll be here often',
                  author: 'Mohammad Sheikh',
                  date: new Date(),
                  helpfulCount: 5,
                  notHelpfulCount: 4
              },
              {
                  rating: 2,
                  reviewText: 'Absolutely horrible. Please stop making food.',
                  author: 'Dissatisfied Customer',
                  date: new Date(),
                  helpCount: 2,
                  notHelpfulCount: 3
              },
          ],
          foods: 
          [
              {
                  id: 0,
                  name: 'Salad',
                  img: 'http://www.images.google.com/',
                  tags: ['vegan', 'low-calorie', 'cheap'],
                  nutrition: 
                  {
                      calories: 300,
                      fat: 5,
                      carbs: 40,
                      protein: 24
                  },
                  reviews: 
                  {
                      rating: 4,
                      reviewText: 'Decent salad. Would recommend.',
                      author: 'Vegan Bro',
                      date: new Date(),
                      helpCount: 4,
                      notHelpfulCount: 1
                  }  
              },
              {
                  id: 1,
                  name: 'Pasta',
                  img: 'http://www.images.google.com/',
                  tags: ['vegetarian', 'dinner'],
                  nutrition: 
                  {
                      calories: 800,
                      fat: 40,
                      carbs: 80,
                      protein: 20
                  },
                  reviews: 
                  {
                      rating: 5,
                      reviewText: 'Absolutely amazing',
                      author: 'Food Fan',
                      date: new Date(),
                      helpCount: 8,
                      notHelpfulCount: 4
                  }  
              },
          ],
      },
  ];
  
  const paperStyle = {
    height: 100,
    width: 100,
    margin: 20,
    textAlign: 'center',
    display: 'table',
    position: 'relative',
    clear: 'both',
    float: 'right',
    zIndex: 6
  };
  
  const paperContent = {
      position: 'absolute',
      top: '50%',
      left: '50%',
      transform: 'translate(-50%, -50%)'
  }
  
  class RestaurantDialog extends React.Component {
      constructor(props) {
          super(props);
          this.state = {
              open: false
          }
      }
  
      render() {
          return (
              &lt;Dialog&gt;
              &lt;/Dialog&gt;
          )
      }
  }
  
  class RestaurantButton extends React.Component {
      constructor(props) {
          super(props);
      }
  
      handleClick = () =&gt; {
  
      }
  
      render() {
          return (
              &lt;FlatButton style={{width: '100%', height: '64px'}} onClick&gt;
                  {this.props.item.city}
                  &lt;RestaurantDialog restaurant={this.props.item.name} /&gt;
              &lt;/FlatButton&gt;
          )
      }
  }
  
  class MapComponent extends React.Component {
  
      constructor(props) {
          super(props);
          this.googleChecker = this.googleChecker.bind(this);
          this.renderMap = this.renderMap.bind(this);
      }
  
      googleChecker() {
          if (!window.google.maps) {
              setTimeout(this.googleChecker, 100);
          }
          else {
              this.renderMap();
          }
      }
  
      renderMap() {
          var map = google.maps.Map(document.getElementById('map'), {
              zoom: 4,
              center: {lat: 0, lng: 0}
          });
      }
  
      componentDidMount() {
          this.googleChecker();
      }
  
      render() {
  
          const selections = this.props.currentSelections;
          const buttons = items.filter((item) =&gt; {
              for (let i = 0; i &lt; selections.length; i++) {
                  if (selections.map((selection) =&gt; {return selection.toLowerCase()}).indexOf(item.tags[i].toLowerCase()) &gt; -1) {
                      return true;
                  }
              }}).map((item) =&gt; {
                  return (
                      &lt;RestaurantButton style={{zIndex: '5'}} item={item} /&gt;
                  )
              });
  
          return (
              &lt;Paper id='map' zDepth={3} style={{height: '300px', width: '100%', backgroundColor: 'white', position: 'absolute'}}&gt;
                  { buttons }
              &lt;/Paper&gt;
          )
      }
  }
  
  class SelectionIcon extends React.Component {
      constructor(props) {
          super(props);
      }
  
      render() {
          return (
              &lt;Paper circle={true} zDepth={5} style={this.props.style} key={this.props.index} onClick={this.props.close} &gt;
                  &lt;div style={paperContent}&gt;{this.props.item}&lt;/div&gt;
              &lt;/Paper&gt;
          )
      }
  }
  
  class SelectionIcons extends React.Component {
      constructor(props) {
          super(props);
  
      }
  
      handleSelectionClose = (e) =&gt; {
          e.currentTarget.open = false;
      }
  
      render() {
  
      let currentSelections = this.props.currentSelections.slice();
      let list = currentSelections.map((item, i) =&gt; {
          return (
              &lt;Paper circle={true} zDepth={5} style={paperStyle} key={i} onClick={this.handleSelectionClose}&gt;
                  &lt;div style={paperContent}&gt;{item}&lt;/div&gt;
              &lt;/Paper&gt;
          )
      });
  
          return (
              &lt;div&gt;
                  {list}
              &lt;/div&gt;
          )
      }
  }
  
  class Main extends React.Component {
      constructor(props){
          super(props);
          this.state = {
              navMenuOpen: false,
              currentSelections: []
          }
  
      }
  
      handleMenuButtonTouch = (e) =&gt; {
          this.setState({
              anchorEl: e.currentTarget.parentNode,
              navMenuOpen: !this.state.navMenuOpen
          })
      }
  
      handleRequestChange = (change) =&gt; {
          this.setState({
              navMenuOpen: change.open
          })
           console.log(document.getElementById('test').style);
      }
  
      handleMenuClick = (e) =&gt; {
          let currentSelections = this.state.currentSelections.slice();
          if (currentSelections.indexOf(e) &gt; -1) {
              currentSelections.splice(currentSelections.indexOf(e), 1);
          }
          else {
              currentSelections.push(e);
          }
          console.log(currentSelections)
          this.setState({ currentSelections });
       }
  
      render() {
          return (
              &lt;div&gt;
                  &lt;AppBar title='The App' id='test' zDepth={1} onLeftIconButtonTouchTap={this.handleMenuButtonTouch} style={{zIndex: 4}}&gt; 
                  &lt;/AppBar&gt;
                  &lt;Drawer 
                          id='test2'
                          open={this.state.navMenuOpen}
                          onRequestChange={() =&gt; {this.handleRequestChange;}}
                          containerStyle={{zIndex: 3, marginTop: '64px'}}&gt;
  
                          &lt;Menu&gt;
                              &lt;MenuItem primaryText='High Protein' onClick={() =&gt; this.handleMenuClick('High Protein')} /&gt;
                              &lt;MenuItem primaryText='Vegetarian' onClick={() =&gt; this.handleMenuClick('Vegetarian')} /&gt;
                              &lt;MenuItem primaryText='Vegan' onClick={() =&gt; this.handleMenuClick('Vegan')} /&gt;
                          &lt;/Menu&gt;
                      &lt;/Drawer&gt; 
                  &lt;MapComponent items={items} currentSelections={this.state.currentSelections} /&gt;
                  &lt;SelectionIcons currentSelections={this.state.currentSelections} /&gt;  
              &lt;/div&gt;
          )
      }
  }
  
  
  export default Main;
  </code></pre>
  
  <p>My index.html: </p>
  
  <pre><code>&lt;!doctype html&gt;
  &lt;html lang="en"&gt;
    &lt;head&gt;  
      &lt;meta charset="utf-8"&gt;
      &lt;meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"&gt;
      &lt;meta name="theme-color" content="#000000"&gt;
      &lt;!--
        manifest.json provides metadata used when your web app is added to the
        homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
      --&gt;
      &lt;link rel="manifest" href="%PUBLIC_URL%/manifest.json"&gt;
      &lt;link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"&gt;
      &lt;link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet"&gt;
      &lt;!--
        Notice the use of %PUBLIC_URL% in the tags above.
        It will be replaced with the URL of the `public` folder during the build.
        Only files inside the `public` folder can be referenced from the HTML.
  
        Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
        work correctly both with client-side routing and a non-root public URL.
        Learn how to configure a non-root public URL by running `npm run build`.
      --&gt;
      &lt;title&gt;React App&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
      &lt;noscript&gt;
        You need to enable JavaScript to run this app.
      &lt;/noscript&gt;
      &lt;script async defer
        src='https://maps.googleapis.com/maps/api/js?key=AIzaSyDZfVO29Iytspv4xz7S68doIoiztiRLhbk'&gt;
      &lt;/script&gt;
      &lt;div id="root"&gt;&lt;/div&gt;
      &lt;!--
        This HTML file is a template.
        If you open it directly in the browser, you will see an empty page.
  
        You can add webfonts, meta tags, or analytics to this file.
        The build step will place the bundled scripts into the &lt;body&gt; tag.
  
        To begin the development, run `npm start` or `yarn start`.
        To create a production bundle, use `npm run build` or `yarn build`.
      --&gt;
    &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>