Search code examples
node.jsreactjswebpackreduxreact-redux

How to implement Google API with React, Redux and Webpack


I'm trying to get google calendar events into my React Redux app.
I've tried using googleapis and google-auth-library but webpack is throwing errors because googleapis was built to run server side and bundle.js is referenced from client. So I've read a few forums about these errors and they all point to using Google's js client library instead.

I understand how to implement this in a java or php app (I'm old... 35 ;) but I'm new to React Redux and I'm looking for the best way to implement this.

I'm trying to fetch the events from my calendar in my actions.js. I tried including <script src="https://apis.google.com/js/api.js"></script> in my html header and then using gapi.load() from actions.js. I also tried creating a api.js file and referencing that with require('./api'). I also tried to use the cli commands from the Node.js Quickstart guide to get an access_token and then just use axios to call Google API directly but I'm getting a 403. I'm thinking I'm just not providing the proper headers but that wouldn't be best practice anyway.

My question is basically how do I reference Google's js client library from my actions.js file while adhering to Redux standards?


Solution

  • I'm going to answer my own question despite some very good correct answers. @MattYao answered my actual question of how to get a js script available for reference in my actions.js file. @Ethan Brown gave a very detailed answer that showed some excellent flow possibilities. @realseanp changed the scope but a valid answer.

    I tried all of the above and they worked.

    So I'm not sure what I was doing wrong but I was finally able to access the gapi object from actions.js by just adding <script src="https://apis.google.com/js/api.js"></script> to my index head. I'm using pug so it looks like this:

    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')
    

    Here is my component file:

    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>
            )
        }
    }
    

    And then I was able to get this working in my actions.js file

    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/[email protected]/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)
    }}
    

    I had to make my calendar public to access it this way. So now I'm going to work on the oauth2 stuff :/