如何使用 React、Redux 和 Webpack 实现 Google API

IT技术 node.js reactjs webpack redux react-redux
2021-04-26 15:56:22

我正在尝试将 google 日历事件添加到我的 React Redux 应用程序中。
我试过使用 googleapis 和 google-auth-library 但 webpack 抛出错误,因为 googleapis 是为运行服务器端而构建的,并且 bundle.js 是从客户端引用的。所以我阅读了一些关于这些错误的论坛,它们都指向使用Google 的 js 客户端库

我了解如何在 java 或 php 应用程序中实现这一点(我老了...... 35 ;)但我是 React Redux 的新手,我正在寻找实现这一点的最佳方法。

我正在尝试从我的 actions.js 中的日历中获取事件。我尝试包含<script src="https://apis.google.com/js/api.js"></script>在我的 html 标题中,然后使用来自 actions.js 的 gapi.load()。我还尝试创建一个 api.js 文件并使用 require('./api') 引用它。我还尝试使用 Node.js快速入门指南中的 cli 命令来获取 access_token,然后仅使用 axios 直接调用 Google API,但我得到了 403。我想我只是没有提供正确的标头但这无论如何都不是最佳实践。

我的问题基本上是如何在遵守 Redux 标准的同时从我的 actions.js 文件中引用 Google 的 js 客户端库?

4个回答

通过在 HTML 标头中包含官方 Google 客户端 API,您走在正确的轨道上。这不太理想——如果谷歌提供(浏览器)客户端 API 作为 npm module,那将会很好import但他们没有(我看到的),所以我认为你在做什么很好。

然后是“我如何以一种对 React/Redux 友好的方式使用它”的问题?Redux 是一种管理应用程序状态的机制Google API 不是您的应用程序的一部分(尽管您对它的操作可能会通知您应用程序的状态)。

很容易验证您是否有权访问 Google API:您只需从componentDidMount您的一个组件方法中进行调用,然后执行控制台日志:

class MyComp extends React.Component {
  componentDidMount() {
    // this is taken directly from Google documentation:
    // https://developers.google.com/api-client-library/javascript/start/start-js
    function start() {
      // 2. Initialize the JavaScript client library.
      gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        // clientId and scope are optional if auth is not required.
        'clientId': 'YOUR_WEB_CLIENT_ID.apps.googleusercontent.com',
        'scope': 'profile',
      }).then(function() {
        // 3. Initialize and make the API request.
        return gapi.client.request({
          'path': 'https://people.googleapis.com/v1/people/me',
        })
      }).then(function(response) {
        console.log(response.result);
      }, function(reason) {
        console.log('Error: ' + reason.result.error.message);
      });
    };
    // 1. Load the JavaScript client library.
    gapi.load('client', start);
  },
}

如果您没有在控制台上看到您所期望的内容,那么不知何故gapi没有按您的预期加载。如果发生这种情况,您可以提出更具体的问题!

如果您确实得到了响应,那么您现在知道如何调用 GAPI……但是如何以对 Redux 友好的方式使用它呢?

当您进行 GAPI 调用时,您可能希望以某种方式修改应用程序的状态(否则为什么要这样做?)例如,您可能会调用身份验证流程,当 GAPI 返回成功时,您的应用程序状态现在具有loggedIn: true或类似(可能还有许多其他状态变化)。在何处进行 GAPI 调用取决于您。如果你想在组件加载时执行,你应该在componentDidMount. 您还可能通常会发出 GAPI 调用以响应用户操作,例如单击按钮。

所以典型的流程是这样的:

// either in componentDidMount, or a control handler, usually:
someGapiCall()
  .then(result => {
    this.props.onGapiThing(result.whatever)
  })

哪里this.props.onGapiThing是一个函数,它调度一个适当的动作,它修改你的应用程序状态。

我希望这个概述有帮助...请随时跟进更具体的问题。

当我找不到 NPM module时,你可以试试这个库,我用来在我的 React 应用程序中加载外部库和module:

https://github.com/ded/script.js/

所以你的代码会是这样的:

import $script from 'scriptjs';

$script('https://apis.google.com/js/api.js', function () {
  //Put your google api functions here as callback
});

尽管有一些非常好的正确答案,我还是要回答我自己的问题。@MattYao 回答了我的实际问题,即如何在我的 actions.js 文件中获取可供参考的 js 脚本。@Ethan Brown 给出了一个非常详细的答案,显示了一些极好的流动可能性。@realseanp 改变了范围,但一个有效的答案。

我尝试了上述所有方法并且它们起作用了。

所以我不确定我做错了什么,但我终于能够通过添加<script src="https://apis.google.com/js/api.js"></script>到我的索引头来从 actions.js 访问 gapi 对象我正在使用 pug 所以它看起来像这样:

doctype
html
    head
        title MyTitle
        link(rel='stylesheet' href='/static/css/main.css')
        link(rel='stylesheet' href='/static/css/react-big-calendar.css')
        script(src='https://apis.google.com/js/api.js' type='text/javascript')
    body
        div(id='app')
        script(src='/static/bundle.js' type='text/javascript')

这是我的组件文件:

import React from 'react'
import BigCalendar from 'react-big-calendar';
import moment from 'moment';
import { connect } from 'react-redux'

import { fetchEvents } from '../actions/actions'

BigCalendar.momentLocalizer(moment);
@connect((store) => {
    return {
        events: store.events.events
    }
})
export default class Calendar extends React.Component 
{
    componentWillMount() 
    {        
        this.props.dispatch(fetchEvents())
    }

    render() 
    {
        return (
            <div>
                <BigCalendar
                    events={this.props.events}
                    startAccessor='startDate'
                    endAccessor='endDate'
                    style={{height: 800}}
                />
            </div>
        )
    }
}

然后我能够在我的 actions.js 文件中使用它

export function fetchEvents() 
{
  return (dispatch) =>
  {
    function start() 
    {
      // 2. Initialize the JavaScript client library.
      gapi.client.init({
        'apiKey': API_KEY,
        // clientId and scope are optional if auth is not required.
        'clientId': CLIENT_ID,
        'scope': 'profile',
      }).then(function() {
        // 3. Initialize and make the API request.
        return gapi.client.request({
          'path': 'https://www.googleapis.com/calendar/v3/calendars/MY_EMAIL@gmail.com/events?timeMax=2017-06-03T23:00:00Z&timeMin=2017-04-30T00:00:00Z',
        })
      }).then( (response) => {
        let events = response.result.items
        dispatch({ 
          type: 'FETCH_EVENTS_FULFILLED',
          payload: events
        })
      }, function(reason) {
        console.log(reason);
      });
    };

    // 1. Load the JavaScript client library.
    gapi.load('client', start)
}}

我必须公开我的日历才能以这种方式访问​​它。所以现在我要处理 oauth2 的东西:/

我会在加载我的 webpack 包(选项 1之前加载我的索引文件中的所有 google 内容然后我会使用redux sagas来调用 google api。在您的 webpack 包之前加载 google 代码将确保当您从 saga 调用 api 时一切准备就绪