32

I want to load the Google APIs client library inside my index.html and the onLoad='someMethod' will invoke a method in a separate javascript file. That method will then print out to the console.

The client library is loaded without any problems but the message is not getting printed out the console and I think it's because the method is not getting invoked at all.

Here is my index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Welcome</title>

    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>

<body>
    <div id="app"></div>
    <script src="lib/vendors.js"></script>
    <script src="build/bundle.js"></script>
    <script src="https://apis.google.com/js/client.js?onload=handleGoogleClientLoad"></script>
</body>

Here is the javascript file that contains the handleGoogleClientLoad method:

import React from 'react';
import ReactDOM from 'react-dom';

import {Button} from 'react-bootstrap';

class MyApp extends React.Component {

handleGoogleClientLoad() {
    console.log('Success on load');
}

render() {
    return (
        <div>
            <Button>Click Me</Button>
        </div>
    );
  }
}


const app = document.getElementById('app');

ReactDOM.render(<MyApp />, app);

If this was plain javascript the method would look like this:

window.handleGoogleClientLoad = function() {
  // Log to the console
};

Is there anything in es6 that is similar to the window object.

3 Answers 3

26

Component methods are not attached to the window object. MyApp.handleGoogleClientLoad is not going to be aliased to window.handleGoogleClientLoad which is what the google API script is likely trying to invoke.

If you want the Google API to call a method on your component you're going to have some trouble as there's no guarantee that your component will be mounted before or after your Google API script loads. If you want to guarantee that you'd have to inject the script after the component mounted and register the function in the componentDidMount method. You can use something like loadjs

componentDidMount() {
 window.handleGoogleClientLoad = function() {
  // log to console
 }
 loadjs('https://apis.google.com/js/client.js?onload=handleGoogleClientLoad')
}
Sign up to request clarification or add additional context in comments.

4 Comments

I haven't tried using loadjs yet but I have added in the componentDidMount() method and it's all working perfectly. Thanks!
What about adding the google API script element to load before the react stuff is loaded? <script src="https://apis.google.com/js/client.js?onload=handleGoogleClientLoad"></script> <script src="lib/vendors.js"></script> <script src="build/bundle.js"></script>
Without using loadjs, how does this tell you the script has loaded? I could create any function, and call it in componentDidMount using the above method, and it will run.
I am not able to call any function that is bound with this in window.handlechange()
2

An old question but I found this while solving the problem myself. I am using React Helmet to put stuff in <head>. How I have done it is below. The key here is using defer when using <script> to load gapi. This means it does not run it until the document has been parsed, meaning our onload function window.gapiInit now exists.

From https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attr-defer:

This Boolean attribute is set to indicate to a browser that the script is meant to be executed after the document has been parsed, but before firing DOMContentLoaded.

import React from "react"

import { Helmet } from "react-helmet"

const HeadHelmet: React.FC = () => {
  if (typeof window != "undefined") { // needed if SSR
    window.gapiInit = () => {
      console.log({ gapiInit: true })
      // set state, what ever you need
    }
  }

  return (
    <Helmet>
      <script
        src="https://apis.google.com/js/api.js?onload=gapiInit"
        defer={true}
      ></script>
    </Helmet>
  )
}

export default HeadHelmet

Comments

0

the window object will still be available to you from your react component.. but the issue is that your defining your function just fine, but you're not calling it anywhere (is that jsonp syntax in the url of that script?). if you want that function to execute when you mount your component, you can make use of the component lifecycle hooks, specifically, componentDidMount

class MyApp extends React.Component {

handleGoogleClientLoad() {
    console.log('Success on load');
}

componentDidMount(){
  this.handleGoogleClientLoad();
}

render() {
    return (
        <div>
            <Button>Click Me</Button>
        </div>
    );
  }
}

if you want to keep the syntax you already have, then you can go ahead and access the window the way you suggest, but its thats definitely not a very react way of doing it

3 Comments

This will call handleGoogleClientLoad when MyApp mounts, not when the Google script has loaded.
is handleGoogleClientLoad actually dependent on your react component?
This doesn't indicate anything about scripts included in the head actually loading. It does indicate that componentDidMount is called, which is no news really.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.