How to Use Google Charts in React

shahednasser

Shahed Nasser

Posted on September 13, 2021

How to Use Google Charts in React

This article was originally published on my personal blog

Google Charts is a free Javascript library that allows you to visualize data in many types of charts and graphs. It's very useful and easy to use in your projects.

In this tutorial, we'll see how to use Google Charts in React by creating a simple React app with Create React App (CRA). We'll learn how to use Google Charts with either hooks or context for different use cases.

You can check the code for this tutorial on this GitHub Repository.

Create React App

We'll start by creating the React app. Run the following command:

npx create-react-app react-google-charts
Enter fullscreen mode Exit fullscreen mode

After the command is done, we'll have a react website created with CRA.

We'll also install react-bootstrap to use some helpful Bootstrap components:

npm install react-bootstrap@next bootstrap@5.1.0
Enter fullscreen mode Exit fullscreen mode

Using Google Charts With Hooks

The first approach we'll check is how to use Google Charts in React with Hooks. The code for this section of the tutorial in the GitHub Repository is under src/WithHooks.

Creating the Hook

Create the file src/useGoogleCharts.js with the following content:

import { useEffect, useState } from "react";

function useGoogleCharts () {
  const [google, setGoogle] = useState(null);

    useEffect(() => {
        if (!google) {
            //TODO load google charts
        }
   }, [google]);

  return google;
}

export default useGoogleCharts;
Enter fullscreen mode Exit fullscreen mode

This creates a new hook that has a state google. This state allows us to check if Google Charts is loaded or not and it will hold the loaded window.google object. Then, we will use useEffect to load the charts when they're not loaded. Finally, we just return google.

In order to load Google Charts, we need to load the script https://www.gstatic.com/charts/loader.js in the <head> of the document, then when it's loaded, we'll load the core package of Google charts. Finally, when the core package is loaded, we'll set google to window.google.

Add the following code inside the if condition:

const head = document.head;
let script = document.getElementById('googleChartsScript');
if (!script) {
    script = document.createElement('script');
    script.src = 'https://www.gstatic.com/charts/loader.js';
    script.id = 'googleChartsScript';
    script.onload = () => {
        if (window.google && window.google.charts) {
            window.google.charts.load('current', {'packages':['corechart']});

            window.google.charts.setOnLoadCallback(() => setGoogle(window.google))
        }
    };
    head.appendChild(script);
} else if (window.google && window.google.charts && window.google.visualization) {
    setGoogle(window.google);
}
Enter fullscreen mode Exit fullscreen mode

We're first checking if the script is already loaded to avoid loading it again.

If the script isn't loaded, we're creating the script element, and we're adding an event listener for onload that will load the code packages of Google Charts.

Then, when the packages are loaded we can set google with setGoogle(window.google).

In case the script has already been loaded, we check if window.google is set then set google.

Finally, we'll return in useEffect the following function:

return () => {
      let script = document.getElementById('googleChartsScript');
      if (script) {
        script.remove();
      }
    }
Enter fullscreen mode Exit fullscreen mode

This removes the script on unmount.

Creating the Chart Component

Next, we'll create the chart component that will draw the chart after the Google Chart library has been loaded.

Create the component src/PizzaChart.js with the following content:

import { useEffect, useState } from "react";
import { Spinner } from "react-bootstrap";

function PizzaChart ({google}) {
  const [chart, setChart] = useState(null);

  useEffect(() => {
    if (google && !chart) {
        //TODO draw the chart
    }
  }, [loaded, chart]);

  return (
    <>
      {!google && <Spinner />}
      <div id="pizzaChart" className={!google ? 'd-none' : ''} />
    </>
  )
}

export default PizzaChart;
Enter fullscreen mode Exit fullscreen mode

This component receives a google prop, which will be the returned value from useGoogleCharts. It has a chart state to ensure that the chart is created only once.

Inside useEffect, we'll check if google is not null and if chart is null. In that case, we'll draw the chart.

Finally, we're just showing a spinner if google is null and we're creating the div element that the chart will go into.

Back to the if condition in useEffect, we need to add the code to draw the chart. We'll add the code from the Google Charts' Pie Chart Example:

// Create the data table.
const data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
    ['Mushrooms', 3],
    ['Onions', 1],
    ['Olives', 1],
    ['Zucchini', 1],
    ['Pepperoni', 2]
]);

// Set chart options
var options = {'title':'How Much Pizza I Ate Last Night',
               'width':400,
               'height':300};

// Instantiate and draw our chart, passing in some options.
const newChart = new google.visualization.PieChart(document.getElementById('pizzaChart'));
newChart.draw(data, options);

setChart(newChart);
Enter fullscreen mode Exit fullscreen mode

We're first collecting the data with the options, then we're using google.visualization to draw the pie chart. Finally, we set the chart state.

Inside src/App.js, replace the content with the following:

import { Container } from "react-bootstrap";
import PizzaChart from "./PizzaChart";
import useGoogleCharts from './useGoogleCharts';

function App() {
  const google = useGoogleCharts();

  return (
    <>
      <Container className="mt-3">
        <h1>With Hooks</h1>
        <PizzaChart google={google} />
      </Container>
    </>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Try running the server now if it isn't running. You'll see a pie chart.

How to Use Google Charts in React

Multiple Charts

Let's try adding another chart. We'll create a new chart component src/DinosaurChart with the following content:

import { useEffect, useState } from "react";
import { Spinner } from "react-bootstrap";

function DinosaurChart ({google}) {
  const [chart, setChart] = useState(null);

  useEffect(() => {
    if (google && !chart) {
      const data = google.visualization.arrayToDataTable([
        ['Dinosaur', 'Length'],
        ['Acrocanthosaurus (top-spined lizard)', 12.2],
        ['Albertosaurus (Alberta lizard)', 9.1],
        ['Allosaurus (other lizard)', 12.2],
        ['Apatosaurus (deceptive lizard)', 22.9],
        ['Archaeopteryx (ancient wing)', 0.9],
        ['Argentinosaurus (Argentina lizard)', 36.6],
        ['Baryonyx (heavy claws)', 9.1],
        ['Brachiosaurus (arm lizard)', 30.5],
        ['Ceratosaurus (horned lizard)', 6.1],
        ['Coelophysis (hollow form)', 2.7],
        ['Compsognathus (elegant jaw)', 0.9],
        ['Deinonychus (terrible claw)', 2.7],
        ['Diplodocus (double beam)', 27.1],
        ['Dromicelomimus (emu mimic)', 3.4],
        ['Gallimimus (fowl mimic)', 5.5],
        ['Mamenchisaurus (Mamenchi lizard)', 21.0],
        ['Megalosaurus (big lizard)', 7.9],
        ['Microvenator (small hunter)', 1.2],
        ['Ornithomimus (bird mimic)', 4.6],
        ['Oviraptor (egg robber)', 1.5],
        ['Plateosaurus (flat lizard)', 7.9],
        ['Sauronithoides (narrow-clawed lizard)', 2.0],
        ['Seismosaurus (tremor lizard)', 45.7],
        ['Spinosaurus (spiny lizard)', 12.2],
        ['Supersaurus (super lizard)', 30.5],
        ['Tyrannosaurus (tyrant lizard)', 15.2],
        ['Ultrasaurus (ultra lizard)', 30.5],
        ['Velociraptor (swift robber)', 1.8]]);

      var options = {
        title: 'Lengths of dinosaurs, in meters',
        legend: { position: 'none' },
      };

      // Instantiate and draw our chart, passing in some options.
      const newChart = new google.visualization.Histogram(document.getElementById('dinosaurChart'));
      newChart.draw(data, options);

      setChart(newChart);
    }
  }, [google, chart]);

  return (
    <>
      {!google && <Spinner />}
      <div id="dinosaurChart" className={!google ? 'd-none' : ''} />
    </>
  )
}

export default DinosaurChart;
Enter fullscreen mode Exit fullscreen mode

This chart component is exactly similar to PizzaChart, except it draws a Histogram rather than a Pie Chart. The code for the data is taken from Google Charts' Histogram Example.

Now, add the new component after PizzaChart in src/App.js in the returned JSX:

<PizzaChart google={google} />
<DinosaurChart google={google} />
Enter fullscreen mode Exit fullscreen mode

If you open the page now, you'll see two charts.

How to Use Google Charts in React

Using Google Charts With Context

You can also use Google Charts with React Contexts. This allows you to use the google object in any component without having to call the hook in one component and pass the google object as a prop to the chart components.

The code for this section is found in the GitHub Repository in the directory src/WithContext.

Create Google Context

First, create src/GoogleContext.js with the following content:

import React from "react";

export default React.createContext({
  google: null,
  setGoogle: () => {}
});
Enter fullscreen mode Exit fullscreen mode

This will create the Google Context with the google object, initially null, and a setter function setGoogle.

Use Context Provider

Inside src/App.js, change the content to the following:

import { useEffect, useState } from "react";
import { Container } from "react-bootstrap";
import GoogleContext from "./GoogleContext";

function App() {
  const [google, setGoogle] = useState(null);

  useEffect(() => {
    if (!google) {
      const head = document.head;
      let script = document.getElementById('googleChartsScript');
      if (!script) {
        script = document.createElement('script');
        script.src = 'https://www.gstatic.com/charts/loader.js';
        script.id = 'googleChartsScript';
        script.onload = () => {
          if (window.google && window.google.charts) {
            window.google.charts.load('current', {'packages':['corechart']});

            window.google.charts.setOnLoadCallback(() => setGoogle(window.google))
          }
        };
        head.appendChild(script);
      } else if (window.google) {
        setGoogle(window.google);
      }
    }

    return () => {
      let script = document.getElementById('googleChartsScript');
      if (script) {
        script.remove();
      }
    }
  }, [google]);

  return (
    <GoogleContext.Provider value={{google, setGoogle}}>
      <Container className="mt-3">
        <h1>With Context</h1>
      </Container>
    </GoogleContext.Provider>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here, we are creating a google state. Then, in useEffect we are executing the same code that we did previously in useGoogleChart. We are loading the script then setting the google state when it's loaded.

Finally, we are surrounding the rendered components with the context provider, passing it the state and its setter as the value.

Create Chart Component

Next, we'll create the chart component src/PizzaChart.js with the following content:

import { useContext, useEffect, useState } from "react";
import { Spinner } from "react-bootstrap";
import GoogleContext from "./GoogleContext";

function PizzaChart () {
  const [chart, setChart] = useState(null);
  const { google } = useContext(GoogleContext);

  useEffect(() => {
    if (google && !chart) {
      // Create the data table.
      var data = new window.google.visualization.DataTable();
      data.addColumn('string', 'Topping');
      data.addColumn('number', 'Slices');
      data.addRows([
        ['Mushrooms', 3],
        ['Onions', 1],
        ['Olives', 1],
        ['Zucchini', 1],
        ['Pepperoni', 2]
      ]);

      // Set chart options
      var options = {'title':'How Much Pizza I Ate Last Night',
                    'width':400,
                    'height':300};

      // Instantiate and draw our chart, passing in some options.
      const newChart = new window.google.visualization.PieChart(document.getElementById('pizzaChart'));
      newChart.draw(data, options);

      setChart(newChart);
    }
  }, [google, chart]);

  return (
    <>
      {!google && <Spinner />}
      <div id="pizzaChart" className={!google ? 'd-none' : ''} />
    </>
  )
}

export default PizzaChart;
Enter fullscreen mode Exit fullscreen mode

This chart component is similar to the previous chart component we created in the previous section.

First, we are creating the state chart to only render the chart once. Then, we're retrieving the context using useContext. After that, we're drawing the chart inside useEffect. Finally, we're rendering a spinner if google is not loaded, and a div element that the chart will be drawn in.

Now, add the component inside the returned JSX in src/App.js:

<GoogleContext.Provider value={{google, setGoogle}}>
      <Container className="mt-3">
        <h1>With Context</h1>
        <PizzaChart />
      </Container>
    </GoogleContext.Provider>
Enter fullscreen mode Exit fullscreen mode

If you open the website now, you'll see the same Pizza Chart we saw when using hooks.

Multiple Charts

We'll create another chart component src/DinosaurChart.js with the following content:

import { useContext, useEffect, useState } from "react";
import { Spinner } from "react-bootstrap";
import GoogleContext from "./GoogleContext";

function DinosaurChart () {
  const [chart, setChart] = useState(null);
  const { google } = useContext(GoogleContext);

  useEffect(() => {
    if (google && !chart) {
      const data = google.visualization.arrayToDataTable([
        ['Dinosaur', 'Length'],
        ['Acrocanthosaurus (top-spined lizard)', 12.2],
        ['Albertosaurus (Alberta lizard)', 9.1],
        ['Allosaurus (other lizard)', 12.2],
        ['Apatosaurus (deceptive lizard)', 22.9],
        ['Archaeopteryx (ancient wing)', 0.9],
        ['Argentinosaurus (Argentina lizard)', 36.6],
        ['Baryonyx (heavy claws)', 9.1],
        ['Brachiosaurus (arm lizard)', 30.5],
        ['Ceratosaurus (horned lizard)', 6.1],
        ['Coelophysis (hollow form)', 2.7],
        ['Compsognathus (elegant jaw)', 0.9],
        ['Deinonychus (terrible claw)', 2.7],
        ['Diplodocus (double beam)', 27.1],
        ['Dromicelomimus (emu mimic)', 3.4],
        ['Gallimimus (fowl mimic)', 5.5],
        ['Mamenchisaurus (Mamenchi lizard)', 21.0],
        ['Megalosaurus (big lizard)', 7.9],
        ['Microvenator (small hunter)', 1.2],
        ['Ornithomimus (bird mimic)', 4.6],
        ['Oviraptor (egg robber)', 1.5],
        ['Plateosaurus (flat lizard)', 7.9],
        ['Sauronithoides (narrow-clawed lizard)', 2.0],
        ['Seismosaurus (tremor lizard)', 45.7],
        ['Spinosaurus (spiny lizard)', 12.2],
        ['Supersaurus (super lizard)', 30.5],
        ['Tyrannosaurus (tyrant lizard)', 15.2],
        ['Ultrasaurus (ultra lizard)', 30.5],
        ['Velociraptor (swift robber)', 1.8]]);

      var options = {
        title: 'Lengths of dinosaurs, in meters',
        legend: { position: 'none' },
      };

      const newChart = new google.visualization.Histogram(document.getElementById('dinosaurChart'));
      newChart.draw(data, options);

      setChart(newChart);
    }
  }, [google, chart]);

  return (
    <>
      {!google && <Spinner />}
      <div id="dinosaurChart" className={!google ? 'd-none' : ''} />
    </>
  )
}

export default DinosaurChart;
Enter fullscreen mode Exit fullscreen mode

The code is very similar to PizzaChart but the data that is being drawn is different, and a Histogram is being drawn instead of a PieChart.

Finally, we need to add the DinosaurChart component in the returned JSX in src/App.js:

return (
    <GoogleContext.Provider value={{google, setGoogle}}>
      <Container className="mt-3">
        <h1>With Context</h1>
        <PizzaChart />
        <DinosaurChart />
      </Container>
    </GoogleContext.Provider>
  );
Enter fullscreen mode Exit fullscreen mode

If you open the website now, you'll see the 2 charts.

Should You Use Context or Hooks?

The approach you use depends on your use case. If you're using one or multiple charts inside the same component, even if as child components, the hook approach can work fine.

However, if you're using multiple charts spread in different components, the best approach would be to use the context.

Conclusion

In this tutorial, we learned how to use Google Charts with React. The implementation can be expanded if necessary based on your use case, as Google Charts have a lot of use cases and packages other than the core packages.

Make sure to check out Google Chart's documentation as well for more information.

💖 💪 🙅 🚩
shahednasser
Shahed Nasser

Posted on September 13, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related