How to Use React Hooks in Your Datagrid & Chart Web Applications

React Hooks was a new addition to the framework when React released version 16.8. It was designed to allow developers to extract stateful logic from components so that they can be reused, and it does not require you to change your component hierarchy. They allow you to "hook" into a React state from function components.

Wijmo has always and will continue to support React. In this article, I'm going to go over how you can use React Hooks to build an application that incorporates Wijmo's React DataGrid, FlexGrid, as well as its chart control, FlexChart. To do so, we will need to take the following steps:

  1. Create the React Application
  2. Import Wijmo's CSS
  3. Add a Data Source
  4. Implement Wijmo DataGrid and Chart
  5. Create Custom Events to Connect Controls

Create the React Application

First, we'll need to create our application. When creating a React application, you must first have Node >= 14.0.0 and npm >= 5.6 installed on your machine. To create your project, run the following command:

npx create-react-app wijmo-app

This will create our application, wijmo-app. Once the application setup has finished, you can run the following commands to start your application:

cd wijmo-app

npm start

Your machine will then open the application in your default browser.

Now that we have our application, it’s time to add Wijmo. Since we're just working with React, we'll only install Wijmo's react interop. To do so, run the following command:

npm install @grapecity/wijmo.react.all

Now that we've got the application set up and Wijmo installed, it’s time to move on to writing the application.

Import Wijmo's CSS

The first thing that we'll want to do is import Wijmo's CSS files. To do so, open your application's index.css file. At the top of the file, include the following line of code:

@import '@grapecity/wijmo.styles/themes/wijmo.theme.material.css';

This will import Wijmo's CSS into your application's main CSS file, ensuring that any components that we build will be stylized correctly. For this application, I'm also going to be using one of Wijmo's themes; the material theme. Wijmo offers dozens of different themes that you can choose from when importing your CSS file. To see what is available, check out our themes sample here.

Add a Data Source

Next, we'll need to implement a data source, what our Wijmo controls will use to populate themselves. For this sample, we'll add a data source within the application. First, create a new folder inside of the application's src folder called data, and a file inside of that folder called data.js:

data.js

Now, we're going to create our data object, as well as 2 functions that we'll be using to retrieve data: getData() and getChartData().

var data = [
    { id: 0, country: 'US', gdp: 20.94, hci: 0.926, gini: 0.48, breakdown: [
        { year: '2000', gdp: 10.25, hci: 0.866, gini: 0.46 },
        { year: '2010', gdp: 14.99, hci: 0.916, gini: 0.47 },
        { year: '2022', gdp: 20.94, hci: 0.926, gini: 0.48 }
    ]},
    { id: 1, country: 'UK', gdp: 2.71, hci: 0.932, gini: 0.34, breakdown: [
        { year: '2000', gdp: 1.66, hci: 0.874, gini: 0.39 },
        { year: '2010', gdp: 2.48, hci: 0.766, gini: 0.34 },
        { year: '2022', gdp: 2.71, hci: 0.932, gini: 0.34 }
    ]},
    { id: 2, country: 'China', gdp: 14.72, hci: 0.761, gini: 0.48, breakdown: [
        { year: '2000', gdp: 1.21, hci: 0.588, gini: 0.42 },
        { year: '2010', gdp: 6.09, hci: 0.699, gini: 0.48 },
        { year: '2022', gdp: 14.72, hci: 0.761, gini: 0.48 }
    ]},
];
 
export function getData() {
    return data;
}
 
export function getChartData(index) {
    for(var i = 0; i < data.length; i++) {
        if(data[i].id == index) {
            return data[i].breakdown;
        }
    }
    return data[0].breakdown;
}

The data source contains some information on basic metrics for different countries. The getData() function will return the entire data object. In contrast, the getChartData() method only returns the breakdown for a single country, determined by an index passed to the function. We'll call getData() and getChartData() in the next section to collect data to populate the controls.

Implement Wijmo's DataGrid and Chart

Now it's time to implement the controls that we'll be using. For this demo, we're going to use Wijmo's React DataGrid, FlexGrid, as well as, FlexChart and ComboBox. Inside our application's src folder, we're going to create another folder, called components, and inside those two files, Dataview.js and Dataview.css:

Dataview.css

Now, inside our Dataview.js file, we'll need to import the files and controls that we'll be using:

import { useRef, useState } from 'react';
import { CollectionView } from '@grapecity/wijmo';
import { FlexGrid, FlexGridColumn } from '@grapecity/wijmo.react.grid';
import { FlexChart, FlexChartLegend, FlexChartAxis, FlexChartSeries } from '@grapecity/wijmo.react.chart';
import { FlexChartAnimation } from '@grapecity/wijmo.react.chart.animation';
import { ComboBox } from '@grapecity/wijmo.react.input';
import { getData, getChartData } from '../data/data'

Now, there's a fair amount of imports here, so I'll break down exactly what we're using here.

React Hooks

The useRef and useState imports are used by React Hooks to create our state variables. We'll use these to manage the state of the functional component.

FlexGrid

For the FlexGrid control, we'll be using the CollectionView, FlexGrid, and FlexGridColumn imports. The FlexGrid import for the control, the FlexGridColumn for managing the datagrid's columns, and the CollectionView for the data source.

FlexChart

For the FlexChart control, we'll be importing the FlexChart module for the control itself, FlexChartLegend, Axis, and Series to allow us to customize the control, and FlexChartAnimation so that when our data source changes, the control displays the change using a smooth animation.

ComboBox

For the ComboBox, we'll be using the ComboBox import for the control and the CollectionView for the data source.

Data Source

Finally, we're importing the data source we created during the previous step.

Next, it's time to implement the controls in markup and add their data sources. First, we'll add the states that we'll use to manage the CollectionViews and the controls that we'll need access to:

function Dataview() {
    const [cv, setCV] = useState(new CollectionView(getData(), {}));
    const [chartCV, setChartCV] = useState(new CollectionView(getChartData(0), {}));
    const flexChart = useRef();
    return (
        <div></div>
    );
}
 
export default Dataview;

As you can see, we're using React Hooks to set the state and manage the CollectionViews, as well as the FlexChart control. We're creating our two state variables: cv and chartCV, and using React's useState() function to set the default state value; in this case, the CollectionView. We're also creating a reference to our FlexChart control, which we'll use to update the control later in the article.

Creating a state variable with React Hooks also sets up a setter method for these state objects. If we ever wanted to return later and set a different CollectionView to our cv variable, we could simply call the setCV method and pass it to our new CollectionView.

Now that we have a connection to our data source, we'll implement the controls inside of markup:

function Dataview() {
    const [cv, setCV] = useState(new CollectionView(getData(), {}));
    const [chartCV, setChartCV] = useState(new CollectionView(getChartData(0), {}));
    const flexGrid = useRef();
    const flexChart = useRef();
    return (
        <div>
            <div>
                <ComboBox itemsSource={cv} displayMemberPath="country"></ComboBox>
            </div>
            <br></br>
            <div>
                <FlexGrid itemsSource={cv} selectionMode="Row">
                    <FlexGridColumn binding="id" header="ID"></FlexGridColumn>
                    <FlexGridColumn binding="country" header="Country"></FlexGridColumn>
                    <FlexGridColumn binding="gdp" header="GDP (T)"></FlexGridColumn>
                    <FlexGridColumn binding="hci" header="HCI" format="g3"></FlexGridColumn>
                    <FlexGridColumn binding="gini" header="Gini Coefficient" width="*"></FlexGridColumn>
                </FlexGrid>
            </div>
            <br></br>
            <div>
                <FlexChart ref={flexChart} itemsSource={chartCV} bindingX="year" header="Breakdown by Decade">
                    <FlexChartLegend position="Bottom"></FlexChartLegend>
                    <FlexChartAxis wjProperty="axisY" title="HCI/Gini Coefficient" axisLine={true}></FlexChartAxis>
                    <FlexChartSeries binding="hci" name="HCI"></FlexChartSeries>
                    <FlexChartSeries binding="gini" name="Gini"></FlexChartSeries>
                    <FlexChartSeries binding="gdp" name="GDP">
                        <FlexChartAxis wjProperty="axisY" position="Right" title="GDP (T)" axisLine={true} min={0}></FlexChartAxis>
                    </FlexChartSeries>
                    <FlexChartAnimation></FlexChartAnimation>
                </FlexChart>
            </div>
        </div>
    );
}
 
export default Dataview;

Here, we're implementing our three controls: ComboBox, FlexGrid, and FlexChart. We're using the cv variable to set the itemsSource for both FlexGrid and the ComboBox. This will allow us to tie these two controls together directly so that when the ComboBox selection is changed, the selected row in FlexGrid will change to match it. We're also using the chartCV variable to set the itemsSource property of the FlexChart.

There are also some additional properties that we're setting for FlexGrid and FlexChart. For the datagrid, we're just setting up some formatting for the columns. For the chart, we're setting up the different series that we're going to display on the chart; in this case, a country's GDP, HCI, and Gini Coefficient statistics. As you can see, we're also setting a second Y-axis in the FlexChart. This is because the scales that we're measuring HCI, Gini, and GDP by will be different. Luckily, FlexChart supports multiple Y-axis for situations just like this.

Now, when we run the application, we should see the following:

Flexchart

Unfortunately, while the ComboBox and FlexGrid are connected and updated to reflect changes, the FlexChart will not update to reflect the selected country. In the next section, we'll create a few custom events to allow the FlexChart to update to match the selection.

Create Custom Events to Connect Controls

The last step is to connect the FlexChart with the FlexGrid and ComboBox. To do so, we will add a custom event to the ComboBox's selectedIndexChanged() event and another to FlexChart's itemsSourceChanged() event.

Markup

<div>
    <ComboBox itemsSource={cv} displayMemberPath="country" selectedIndexChanged={selectedIndexChanged}></ComboBox>
</div>
...
<div>
    <FlexChart ref={flexChart} itemsSource={chartCV} bindingX="year" header="Breakdown by Decade" itemsSourceChanged={itemsSourceChanged}>
        <FlexChartLegend position="Bottom"></FlexChartLegend>
        <FlexChartAxis wjProperty="axisY" title="HCI/Gini Coefficient" axisLine={true}></FlexChartAxis>
        <FlexChartSeries binding="hci" name="HCI"></FlexChartSeries>
        <FlexChartSeries binding="gini" name="Gini"></FlexChartSeries>
        <FlexChartSeries binding="gdp" name="GDP">
            <FlexChartAxis wjProperty="axisY" position="Right" title="GDP (T)" axisLine={true} min={0}></FlexChartAxis>
        </FlexChartSeries>
        <FlexChartAnimation></FlexChartAnimation>
    </FlexChart>
</div>

JS

function selectedIndexChanged(s, e) {
    flexChart.current.control.collectionView.sourceCollection = getChartData(s.selectedIndex);
}
function itemsSourceChanged(s, e) {
    s.refresh();
}

Here, we're calling our selectedIndexChanged() method when the ComboBox selectedIndex value is changed. Since this index is changed when a user either changes the ComboBox selection or selects a different row in the datagrid, this event will fire for both cases, allowing us to tie the FlexGrid, FlexChart, and ComboBox together in a single event. Inside, we're just updating the value of the FlexChart's sourceCollection based on the newly selected country's breakdown. We're also forcing a refresh on the FlexChart when its itemsSource property is changed, so the FlexChart will properly reflect the new country's value.

Now, when you select different values in the datagrid or dropdown, the chart will also change to reflect the selected country's information breakdown:

And that's it! Using Wijmo with React Hooks is just as simple as using Wijmo with React Component Classes. If you'd like to download the application created in this article, you can find it here.

Happy coding!

Tags:

comments powered by Disqus