How to Integrate Google Calendar API with React JS?

18,227

Solution 1

Finally adding my solution which worked to help future comers :)

To get the list of events, authorization is not required. So removed the unnecessary code from google's quickstart example.

componentDidMount = () => {
  this.getEvents();
}

getEvents(){
  let that = this;
  function start() {
    gapi.client.init({
      'apiKey': GOOGLE_API_KEY
    }).then(function() {
      return gapi.client.request({
        'path': `https://www.googleapis.com/calendar/v3/calendars/${CALENDAR_ID}/events`,
      })
    }).then( (response) => {
      let events = response.result.items
      that.setState({
        events
      }, ()=>{
        console.log(that.state.events);
      })
    }, function(reason) {
      console.log(reason);
    });
  }
  gapi.load('client', start)
}

You can find the full code and functional demo here.

Solution 2

I'm using a HOC to load the google API:

import React from "react";
import { API_KEY } from "./constants";
import LoadingIndicator from "./common/LoadingIndicator";

export default function withGoogleApps(WrappedComponent) {
  class ComponentWithGoogleAPI extends React.Component {
    state = { gapiReady: false };

    componentDidMount() {
      this.loadGoogleAPI();
    }

    loadGoogleAPI() {
      const script = document.createElement("script");
      script.src = "https://apis.google.com/js/client.js";

      script.onload = () => {
        window.gapi.load("client", () => {
          window.gapi.client.setApiKey(API_KEY);
          window.gapi.client.load("calendar", "v3", () => {
            this.setState({ gapiReady: true });
          });
        });
      };

      document.body.appendChild(script);
    }

    render() {
      const { gapiReady } = this.state;
      if (gapiReady) return <WrappedComponent />;
      return <LoadingIndicator />;
    }
  }
  return ComponentWithGoogleAPI;
}

The you call it like this:

import withGoogleApps from "./withGoogleApps";

const AppConGoogle = withGoogleApps(App);

Then you can call gogle API's like calendar, for example:

const event = this.buildEventoGoogle(values);

const request = window.gapi.client.calendar.events.insert({
      calendarId: "primary",
      resource: event
});

Solution 3

You moved gapi config variables outside of the component, but didn't remove them from initClient parameters so they couldn't be accessed. Here's proper code:

var CLIENT_ID = '992549188018-3prg54pp18je3e3qhgcttgl11491c4dm.apps.googleusercontent.com';
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
var SCOPES = "https://www.googleapis.com/auth/calendar";

class App extends React.Component{
  constructor(props) {
    super(props);
    this.state = {
      showAuthButton: false,
      showSignOutButton: false
    };
    this.initClient = this.initClient.bind(this);
    this.updateSigninStatus = this.updateSigninStatus.bind(this);
  }
  handleAuthClick(){
    gapi.auth2.getAuthInstance().signIn();
  }
  handleSignoutClick(){
    gapi.auth2.getAuthInstance().signOut();
  }
  handleClientLoad() {
    gapi.load('client:auth2', this.initClient);
  }
  initClient(/****here you've had parameters that made config vars unaccessible*****/) {
    gapi.client.init({
      discoveryDocs: DISCOVERY_DOCS,
      clientId: CLIENT_ID,
      scope: SCOPES
    }).then(function () {
      console.log(window.gapi);
      // Listen for sign-in state changes.

      // ************* to access instance method you have to use `this.updateSigninStatus`  
  window.gapi.auth2.getAuthInstance().isSignedIn.listen(this.updateSigninStatus);

      // Handle the initial sign-in state.
      updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());

      // **************this code is unnecessary and causes errors***** 
      // authorizeButton.onclick = handleAuthClick;
      // signoutButton.onclick = handleSignoutClick;
    });
  }
  updateSigninStatus(isSignedIn) {
    if (isSignedIn) {
      this.setState({
        showAuthButton: false,
        showSignOutButton: true
      })
      //listUpcomingEvents();
      //insertNewEvent();
    } else {
      this.setState({
        showAuthButton: true,
        showSignOutButton: false
      })
    }
  }
  componentDidMount(){
    this.handleClientLoad();
  }
  render(){
    let authButton = <button id="authorize-button" onClick={this.handleAuthClick.bind(this)}>Authorize</button>
    let signOutButton = <button id="signout-button" onClick={this.handleSignoutClick.bind(this)}>Sign Out</button>
    return(
      <div className="container">
        {this.state.showAuthButton ? authButton : null}
        {this.state.showSignOutButton ? signOutButton : null}
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
Share:
18,227
Sivadass N
Author by

Sivadass N

Front-end developer who just love to see the pixels moving on the screen when web inspector is doing magic :)

Updated on June 04, 2022

Comments

  • Sivadass N
    Sivadass N about 2 years

    I am trying to implement this vanilla js example of google calendar api in a react js app. The vanilla JS example works just fine in my local machine. But am getting lot of troubles when implementing the same in react. Please check my code below:

    class App extends React.Component{
      constructor(props) {
        super(props);
        var CLIENT_ID = '992549188018-3prg54pp18je3e3qhgcttgl11491c4dm.apps.googleusercontent.com';
        var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/calendar/v3/rest"];
        var SCOPES = "https://www.googleapis.com/auth/calendar";
        this.state = {
          showAuthButton: false,
          showSignOutButton: false
        };
        this.initClient = this.initClient.bind(this);
        this.updateSigninStatus = this.updateSigninStatus.bind(this);
      }
      handleAuthClick(){
        gapi.auth2.getAuthInstance().signIn();
      }
      handleSignoutClick(){
        gapi.auth2.getAuthInstance().signOut();
      }
      handleClientLoad() {
        gapi.load('client:auth2', this.initClient);
      }
      initClient(DISCOVERY_DOCS, CLIENT_ID, SCOPES) {
        gapi.client.init({
          discoveryDocs: DISCOVERY_DOCS,
          clientId: CLIENT_ID,
          scope: SCOPES
        }).then(function () {
          console.log(window.gapi);
          // Listen for sign-in state changes.
          window.gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
    
          // Handle the initial sign-in state.
          updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
          authorizeButton.onclick = handleAuthClick;
          signoutButton.onclick = handleSignoutClick;
        });
      }
      updateSigninStatus(isSignedIn) {
        if (isSignedIn) {
          this.setState({
            showAuthButton: false,
            showSignOutButton: true
          })
          //listUpcomingEvents();
          //insertNewEvent();
        } else {
          this.setState({
            showAuthButton: true,
            showSignOutButton: false
          })
        }
      }
      componentDidMount(){
        this.handleClientLoad();
      }
      render(){
        let authButton = <button id="authorize-button" onClick={this.handleAuthClick.bind(this)}>Authorize</button>
        let signOutButton = <button id="signout-button" onClick={this.handleSignoutClick.bind(this)}>Sign Out</button>
        return(
          <div className="container">
            {this.state.showAuthButton ? authButton : null}
            {this.state.showSignOutButton ? signOutButton : null}
          </div>
        )
      }
    }
    
    ReactDOM.render(
      <App />,
      document.getElementById('root')
    );
    

    Am getting this error as of now:

    Uncaught TypeError: Cannot read property 'isSignedIn' of null

    Please guide me to move further...