сообщение «GAPI не определен»

#javascript #reactjs #google-sheets

#javascript #reactjs #google-таблицы

Вопрос:

Я пытаюсь использовать API Google Sheets для включения в мое веб-приложение, но я продолжаю получать сообщение об ошибке, указывающее, что библиотека gapi не определена. Я пытался отложить запрос на сервер, используя метод жизненного цикла componentDidMount и даже используя тайм-аут в этом методе, но я продолжаю получать ту же ошибку. Как я могу определить библиотеку gapi для использования в моем приложении?

 import React from 'react';
var CLIENT_ID = ''; 
var SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"];


export default class MyNavbar extends React.Component {

  constructor(props) {
    super(props);
  }

  componentDidMount(){
     this.checkAuth();

   }

      /**
       * Check if current user has authorized this application.
       */      
    checkAuth(){
        gapi.auth.authorize(
          {
            'client_id': CLIENT_ID,
            'scope': SCOPES.join(' '),
            'immediate': true
          }, this.handleAuthResult());
      }

      /**
       * Handle response from authorization server.
       *
       * @param {Object} authResult Authorization result.
       */
      handleAuthResult(authResult) {
        var authorizeDiv = document.getElementById('authorize-div');
        if (authResult amp;amp; !authResult.error) {
          // Hide auth UI, then load client library.
          authorizeDiv.style.display = 'none';
          loadSheetsApi();
        } else {
          // Show auth UI, allowing the user to initiate authorization by
          // clicking authorize button.
          authorizeDiv.style.display = 'inline';
        }
      }

      /**
       * Initiate auth flow in response to user clicking authorize button.
       *
       * @param {Event} event Button click event.
       */
     handleAuthClick(event) {
        gapi.auth.authorize(
          {client_id: CLIENT_ID, scope: SCOPES, immediate: false},
          handleAuthResult);
        return false;
      }

      /**
       * Load Sheets API client library.
       */
     loadSheetsApi() {
        var discoveryUrl =
            'https://sheets.googleapis.com/$discovery/rest?version=v4';
        gapi.client.load(discoveryUrl).then(listMajors);
      }

      /**
       * Print the names and majors of students in a sample spreadsheet:
       * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
       */
      listMajors() {
        gapi.client.sheets.spreadsheets.values.get({
          spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms',
          range: 'Class Data!A2:E',
        }).then(function(response) {
          var range = response.result;
          if (range.values.length > 0) {
            appendPre('Name, Major:');
            for (i = 0; i < range.values.length; i  ) {
              var row = range.values[i];
              // Print columns A and E, which correspond to indices 0 and 4.
              appendPre(row[0]   ', '   row[4]);
            }
          } else {
            appendPre('No data found.');
          }
        }, function(response) {
          appendPre('Error: '   response.result.error.message);
        });
      }

      /**
       * Append a pre element to the body containing the given message
       * as its text node.
       *
       * @param {string} message Text to be placed in pre element.
       */
      appendPre(message) {
        var pre = document.getElementById('output');
        var textContent = document.createTextNode(message   'n');
        pre.appendChild(textContent);
      }


   render(){
      return (
        <div>
          <h1>Hello World My Name Is Justin 2</h1>
          <div id="authorize-div"></div>
          <pre id="output"></pre>   
        </div>
      );
    }
}
  

Комментарии:

1. Задержка не поможет вам загрузить библиотеку gapi. Не могли бы вы опубликовать весь файл целиком?

Ответ №1:

Вот попробуйте это.

 import React from 'react';
import asyncLoad from 'react-async-loader'; // for loading script tag asyncly `npm i --save react-async-loader`

const CLIENT_ID = '';
const SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"];

// For making gapi object passed as props to our component
const mapScriptToProps = state => ({
   // gapi will be this.props.gapi
   gapi: {
      globalPath: 'gapi',
      url: 'https://your-gapi-url'
   }
});

@asyncLoad(mapScriptToProps)
class MyNavbar extends React.Component {

  constructor(props) {
    super(props);
    this.gapi = null;
    // You need to bind methods to this class's object context. (i.e this)!
    this.checkAuth = this.checkAuth.bind(this);
    this.handleAuthResult = this.authResult.bind(this);
    this.handleAuthClick = this.handleAuthClick.bind(this);
    this.loadSheetsApi = this.loadSheetsApi.bind(this);
    this.listMajors = this.listMajors.bind(this);
  }

  componentDidMount() {
    // Check is gapi loaded?
    if (this.props.gapi !== null) {
       this.checkAuth();
    }
  }

  componentWillReceiveProps({ gapi }) {
    if (gapi!== null) {
      this.checkAuth();
    }
  }

   /**
   * Check if current user has authorized this application.
   */
  checkAuth() {

    // this will give you an error of gapi is not defined because there is no
    // reference of gapi found globally you cannot access global object which are
    // not predefined in javascript( in this case its window.gapi ).
    // properties added by Programmer cannot be accessed directly( if it's not in the same file as well as the same scope!) in commonjs modules. Because they
    // don't' run in a global scope. Any variable in another module which is not
    // exported, will not be available to other modules.

    this.gapi = window.gapi; // you can do like this. Now you can access gapi in all methods if this class.
    this
        .gapi
        .auth
        .authorize({
            'client_id': CLIENT_ID,
            'scope': SCOPES.join(' '),
            'immediate': true
        }, this.handleAuthResult());
  }

   /**
   * Handle response from authorization server.
   *
   * @param {Object} authResult Authorization result.
   */
  handleAuthResult(authResult) {
    var authorizeDiv = document.getElementById('authorize-div');
    if (authResult amp;amp; !authResult.error) {
        // Hide auth UI, then load client library.
        authorizeDiv.style.display = 'none';
        loadSheetsApi();
    } else {
        // Show auth UI, allowing the user to initiate authorization by clicking
        // authorize button.
        authorizeDiv.style.display = 'inline';
    }
  }

  /**
   * Initiate auth flow in response to user clicking authorize button.
   *
   * @param {Event} event Button click event.
   */
  handleAuthClick(event) {
    // gapi.auth.authorize(  here also gapi is not defined  
     this
        .gapi
        .auth
        .authorize({
            client_id: CLIENT_ID,
            scope: SCOPES,
            immediate: false
        }, handleAuthResult);
    return false;
  }

  /**
   * Load Sheets API client library.
   */
  loadSheetsApi() {
    var discoveryUrl = 'https://sheets.googleapis.com/$discovery/rest?version=v4';
    // also will give your error
    // for gapi being not defined.
    // gapi.client.load(discoveryUrl).then(listMajors); 
    this
        .gapi
        .client
        .load(discoveryUrl)
        .then(listMajors);
  }

  /**
   * Print the names and majors of students in a sample spreadsheet:
   * https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
   */
  listMajors() {
    this.gapi
        .client
        .sheets
        .spreadsheets
        .values
        .get({spreadsheetId: '1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms', range: 'Class Data!A2:E'})
        .then(function (response) {
            var range = response.result;
            if (range.values.length > 0) {
                appendPre('Name, Major:');
                for (i = 0; i < range.values.length; i  ) {
                    var row = range.values[i];
                    // Print columns A and E, which correspond to indices 0 and 4.
                    appendPre(row[0]   ', '   row[4]);
                }
            } else {
                appendPre('No data found.');
            }
        }, function (response) {
            appendPre('Error: '   response.result.error.message);
        });
  }

 /**
   * Append a pre element to the body containing the given message
   * as its text node.
   *
   * @param {string} message Text to be placed in pre element.
   */
  appendPre(message) {
    // as you can see. You are accessing window.document as document. 
    // its fine because its defined in javascript (implicitly),
    // not explicitly by programmer(here you!).
    var pre = document.getElementById('output'); 
    var textContent = document.createTextNode(message   'n');
    pre.appendChild(textContent);
  }

  render() {
    return (
        <div>
            <h1>Hello World My Name Is Justin 2</h1>
            <div id="authorize-div"></div>
            <pre id="output"></pre>
        </div>
    );
  }
}

export default MyNavbar;
  

Ответ №2:

Вам необходимо загрузить gapi библиотеку перед bundle.js в index.html файл, или лучше, вы можете загрузить gapi js-скрипт асинхронно с помощью react-async-loader. Вот как вы можете это сделать :

 import React, { Component, PropTypes } from 'react';
import asyncLoad from 'react-async-loader'; // for loading script tag asyncly

// For making gapi object passed as props to our component
const mapScriptToProps = state => ({
   gapi: {
     globalPath: 'gapi',
     url: 'https://your-gapi-url'
   }
});
// decorate our component
@asyncLoad(mapScriptToProps)
class yourComponent extends Component {
    componentDidMount() {
      // Check is gapi loaded?
      if (this.props.gapi !== null) {
         this.checkAuth();
      }
    }

    componentWillReceiveProps({ gapi }) {
      if (gapi!== null) {
        this.checkAuth();
      }
    }

    checkAuth = () => {
      // Better check with window and make it available in component
      this.gapi = window.gapi;
      this.gapi.auth.authorize({
        'client_id': CLIENT_ID,
        'scope': SCOPES.join(' '),
        'immediate': true
      }, this.handleAuthResult);
    }

    handleAuthResult = (authData) => {
       // Your auth loagic...
    }

    render() {
       return ( <div>
                  { this.props.gapi amp;amp;
                    <YourSpreadsheetOrWhatever data={ this.getData() } />
                  }
            </div>)
    }
}
  

Попробуйте заменить свой код этим и проверьте, работает ли он.

Ответ №3:

Я нашел этот проект https://github.com/rlancer/gapi-starter это может быть полезно.

Google Login amp; API ReactJS Flow Webpack starter kit

API Google великолепны, но они были разработаны до того, как стал популярным модульный партнер по программированию на Javascript. Этот стартер исправляет передачу входа в Google и загрузку библиотеки для вас.

Получите код!

git clone https://github.com/rlancer/gapi-starter.git установка нпм с компакт-диска gapi-starter

Ответ №4:

Вам необходимо загрузить библиотеку gapi, прежде чем bundle.js в index.html файл как :

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

И тогда вам просто нужно инициализировать ваши переменные gapi как :

 let gapi = window.gapi;