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
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
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;
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);
}
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();
}
}
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;
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);
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;
Try running the server now if it isn't running. You'll see a pie chart.
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;
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} />
If you open the page now, you'll see two charts.
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: () => {}
});
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;
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;
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>
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;
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>
);
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.
Top comments (0)