admin管理员组

文章数量:1429558

I am trying to use the gmail API with React.js.

I keep getting the error 'gapi is not defined'. I believe my client.js file in the HTML is loading after my mail.js file runs?

How can I get around this?

Index.html

...
<script src=".js"></script>

Index.js

import './Mail.js';

Mail.js

import { createAction, handleActions } from 'redux-actions'

const CLIENT_ID = '1.apps.googleusercontent'
const SCOPES = ['.readonly']

export const SET_GMAIL_CREDENTIALS = 'SET_GMAIL_CREDENTIALS'
export const CHANGE_LOADING = 'CHANGE_LOADING'
export const SET_GMAIL_LABELS = 'SET_GMAIL_LABELS'
export const SELECT_GMAIL_LABEL = 'SELECT_GMAIL_LABEL'
export const SET_GMAIL_EMAILS = 'SET_GMAIL_EMAILS'

let defaultState = {
  profile: {
    emailAddress: ''
  },
  loading: true,
  labels: [],
  currentLabel: null,
  emails: []
}

export const connect = () => {
  return (dispatch, getState) => {
    dispatch(turnLoadingOn())
    gmailAuth(false, populateCredentials(dispatch), clearCredentials(dispatch))
  }
}...

I am trying to use the gmail API with React.js.

I keep getting the error 'gapi is not defined'. I believe my client.js file in the HTML is loading after my mail.js file runs?

How can I get around this?

Index.html

...
<script src="https://apis.google./js/client.js"></script>

Index.js

import './Mail.js';

Mail.js

import { createAction, handleActions } from 'redux-actions'

const CLIENT_ID = '1.apps.googleusercontent.'
const SCOPES = ['https://www.googleapis./auth/gmail.readonly']

export const SET_GMAIL_CREDENTIALS = 'SET_GMAIL_CREDENTIALS'
export const CHANGE_LOADING = 'CHANGE_LOADING'
export const SET_GMAIL_LABELS = 'SET_GMAIL_LABELS'
export const SELECT_GMAIL_LABEL = 'SELECT_GMAIL_LABEL'
export const SET_GMAIL_EMAILS = 'SET_GMAIL_EMAILS'

let defaultState = {
  profile: {
    emailAddress: ''
  },
  loading: true,
  labels: [],
  currentLabel: null,
  emails: []
}

export const connect = () => {
  return (dispatch, getState) => {
    dispatch(turnLoadingOn())
    gmailAuth(false, populateCredentials(dispatch), clearCredentials(dispatch))
  }
}...
Share Improve this question asked Nov 15, 2016 at 14:03 YconYcon 1,9506 gold badges32 silver badges56 bronze badges 1
  • is your gmail-api script tag after your bundled react/application script tag? – Conan Commented Nov 15, 2016 at 15:09
Add a ment  | 

2 Answers 2

Reset to default 6

I think you're right. The way I'm handling these situations is by loading the external JS file from React and using it in a promise.

So your flow should be something like this:

  1. React app loads
  2. React app injects your file in the HTML
  3. Do your thing in step 2's callback or .then()

Create a helper function. Put it in a folder like helpers/load-script. Below you have all the code you should have in that file:

export default function loadScript(url, cb) {

      var scr = document.createElement('script');
      scr.type = 'text/javascript';

      if (scr.readyState) { // IE
        scr.onreadystatechange = function() {
          if (scr.readyState ==`loaded' || scr.readyState ==='plete') {
            scr.onreadystatechange = null;
            cb();
          }
        };
      } else { // Others
        scr.onload = cb;
      }

      script.src = url;
      document.getElementsByTagName('head')[0].appendChild(scr);
    }

Next, import that function inside the ponent you want to use it into:

import React from 'react';
import loadScript from 'helpers/load-script';

class testComponent extends React.Component {
    
  ponentDidMount() {
    loadScript('https://apis.google./js/client.js', () => {
    // do mail api stuff here               
    });
  }
   
  render() {
    return (
      <div>hi there</div>
    );
  }
}

export default testComponent;

I had the same problem with GrowSurf Javascript Web API, The external script loaded after the render function, and its function was being undefined in ponentDidMount(). This is a logic I used to get the GrowSurf function not to be undefined. It can also help anyone who wants to use a function of any external JS introduced in index.html.

You can use DOMSubtreeModified in ponentDidMount() to check every time the DOM is modified, once the external JS is loaded(found) run your function there, and then stop the looping of DOMSubtreeModified.

ponentDidMount() {
    let functionDefined = false;
    window.addEventListener('DOMSubtreeModified', function () {
        if(!functionDefined) {
            if (window.growsurf) {
                console.log('a function is defined', window.growsurf.getReferrerId());
                functionDefined = true;
            }
        }   
    }, false);
}

For your case, you can simply do this.

ponentDidMount() {
    let functionDefined = false;
    window.addEventListener('DOMSubtreeModified', function () {
        if(!functionDefined) {
            if (window.gapi) {
                // do mail api stuff here       
                functionDefined = true;
            }
        }   
    }, false);
}

本文标签: javascriptReact only run file once external js file loaded (gapi not defined)Stack Overflow