2

I've integrated the Google analytics Embed API with my React app and I'm able to render correctly a graph. This is my container, which renders a line chart through the component UsersChart:

class StatsContainer extends Component {
    constructor(props) {
        super(props);
        initAnalyticsAPI();
    }

    render() {
      return (
         <Query query={GET_ACCESS_TOKEN}>
          {({ loading: loadingToken, error: errorToken, data: { getAnalyticsAccessToken } }) => (
              <Query query={GET_BASIC_STATS}>
                  {({ loading: loadingStats, error: errorStats, data: { getBasicStats } }) => {
                    if (loadingToken || loadingStats) return 'Loading...';
                    if (errorStats) return `Error! ${errorStats.message}`;
                    else if (errorToken) return `Error! ${errorToken.message}`;

                    const token = getAnalyticsAccessToken;

                    return (
                      <Fragment>
                        <div className="stats-container">
                          {/* ... */
                          <UsersCharts token={token} />
                        </div>
                      </Fragment>
                    );
                  }}
              </Query>
        )}
        </Query>
    );
  }
}

initAnalyticsAPI just appends the script to the document, using the official code:

function loadGA() {
   /* eslint-disable */
    (function(w,d,s,g,js,fs) {
        g = w.gapi || (w.gapi={});
        g.analytics = { q:[], ready: function(f) { this.q.push(f); }};
        js = d.createElement(s); fs = d.getElementsByTagName(s)[0];
        js.src='https://apis.google.com/js/platform.js';
        fs.parentNode.insertBefore(js,fs);
        js.onload = function() {
            g.load('analytics');
        };
      }(window, document, 'script'));
    /* eslint-enable */
}

export default function initialize() {
    if (typeof window === 'undefined') {
        return false;
    }

    // avoid downloading the library multiple times if it's already defined
    if (_.isEmpty(window.gapi)) {
        loadGA();
    }

    return window.gapi;
}

To keep it short, UsersCharts renders immediately the container used by the chart, while Google API will load it as soon as it's ready:

class UsersCharts extends Component {
    constructor(props) {
        super(props);
        this.chart = null;
    }

    componentWillUnmount() {
       // how to properly unmount it?
    }

    render() {
        const { token } = this.props;
        window.gapi.analytics.ready(() => {
            /**  Authorize the user with an access token obtained server side. */
            window.gapi.analytics.auth.authorize({
                serverAuth: {
                    access_token: token,
                },
            });

            this.chart = new window.gapi.analytics.googleCharts.DataChart({
            query: {
               ...
            },
            chart: {
                ...
            },
         });
        this.chart.execute();
      });

      return (
          <Fragment>
              <div id="chart-container" />
          </Fragment>
      );
    }
}

The issue is that sometimes I get the following error when I go to another section, which implies that the container for the chart doesn't exist anymore inside the app since another component is rendered. What could I do to properly unmount the component? I search for an API which could allow me to unregister the chart, or at least to catch the error but I wasn't able to find it. Thanks

enter image description here

1 Answer 1

2

Doing a refactoring of UsersChart by mapping the status of both the library and the component, I was able to get rid of all the warnings:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class UsersCharts extends Component {
    constructor(props) {
        super(props);

        this._isMounted = false;
        this.state = {
            ready: false,
        };
    }

    componentDidMount() {
        this._isMounted = true;
        window.gapi.analytics.ready(() => {
            console.log('Ready to do fireworks');
            if (this._isMounted) {
                 this.setState({ ready: true });
            }
        });
    }

    componentWillUnmount() {
        this._isMounted = false;
    }

    render() {
        const { token } = this.props;

       if (this.state.ready) {
        /**  auth and draw chart */

        this.chart.execute();
       }

       return <div id="chart-container" />;
   }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.