loading...

Towards Business Intelligence with React Hooks: Creating a Reporting App

veronikaro profile image Nika ・7 min read

React Hooks Business Intelligence App
The community seems to be split about React Hooks - a new concept introduced in the 16.8.0 release of React. While some developers met it with warmth, others have mixed feelings about it. One thing is certain - React Hooks is a hotly discussed topic in the React community that deserves to be studied more carefully.

In light of its popularity, I’ve decided to do my best to give you a better idea of hooks as a concept and show how to use them to build a React app empowered with an interactive dashboard for financial reporting.

Here's what you'll get as a result of completing the tutorial:

React dashboard with Flexmonster

Ready?

Let’s start!

The motivation behind React Hooks

First, let’s figure out what React Hooks are all about. The main purpose of hooks is to allow using state management, side-effects and many other React features in function components.
The great about it is that you can avoid writing redundant components as containers for business logic since it can be successfully encapsulated in hooks.
For this reason, hooks come in handy when you have a lot of shared logic between components. With them, you are more likely to avoid the wrapper hell in React and flatten your component’s tree structure. Also, many note that hot reloading and optimization can be performed faster using hooks.

Plus, many developers acknowledge that it’s easier to write tests for hooks than for class components.

Finally yet importantly - function components with hooks tend to be more lightweight than their class alternatives.

It’s up to you to decide whether to use hooks in your project or not. To my mind, the power of React in general and this novelty, in particular, is that you are free to choose the world you like the most - OOP or functional programming.

Building a React app with hooks

Let's move on to gaining hands-on experience with hooks. In this section, I’d like to show you how it’s easy to create a user interface for a simple yet powerful analytic application writing minimum lines of code.

Data visualization tool for React

To meet requirements on analytical functionality (namely pivoting and charting), we'll use Flexmonster Pivot Table & Charts. Why? Currently, it’s the only JavaScript library for web reporting I could find that supports React Hooks out-of-the-box. Besides, it’s compatible with the latest version of React.

For demonstration purposes, we'll create a single-page application using the Create React App environment.

The next action is to set up a reporting tool inside our React project. For this, we need to take only three straightforward steps. If you want to skip the configuring steps and go straight to working with the library inside the React app, you can download a ready-to-use project from GitHub, run it and customize according to your needs.

But I recommend getting the feel of configuring the reporting solution by walking through the following guidelines:

  1. After you set up a React project, run the following command to install the Flexmonster React module:
npm i react-flexmonster --save
  1. Create a new PivotTableHooks.js file in the src folder and include FlexmonsterReact into it:
import * as FlexmonsterReact from 'react-flexmonster/hooks';

In this file, we’ll be designing our function component.
First, let's create a variable that holds the JSON data set to be analyzed later:

const dataset = [{
        "Revenue": {
            "type": "number"
        },
        "Burn Rate": {
            "type": "number"
        },
        "Net Sales": {
            "type": "number"
        },
        "Expenses": {
            "type": "number"
        },
        "Date": {
            "type": "date"
        },
        "Date Time": {
            "type": "date string"
        },
        "Discount": {
            "type": "number"
        }
    },
    {
        "Burn Rate": 0.01,
        "Revenue": 455,
        "Net Sales": 250,
        "Expenses": 55,
        "Date": "2018-02-14T07:34:08",
        "Date Time": "2018-02-14T07:34:08",
        "Discount": 45
    },
    /// ... 
]

Secondly, create references to different instances of Flexmonster, namely a pivot table and pivot charts (there can be as many of them as you wish). All these components will be the elements of our future dashboard for financial reporting:

const pivot_ref = React.useRef();
const column_chart_ref = React.useRef();
const line_chart_ref = React.useRef();
const line_chart2_ref = React.useRef();
const line_chart3_ref = React.useRef();

Next, define multiple report objects and set them to different pivot and chart instances:

const pivot_report = {
    dataSource: {
        data: dataset
    },
    "slice": {
        "reportFilters": [{
            "uniqueName": "Date.Year",
            "filter": {
                "members": [
                    "date.year.[2018]",
                    "date.year.[2019]"
                ]
            }
        }],
        "rows": [{
            "uniqueName": "Date.Month"
        }],
        "columns": [{
            "uniqueName": "[Measures]"
        }],
        "measures": [{
                "uniqueName": "Revenue",
                "aggregation": "sum"
            },
            {
                "uniqueName": "Discount",
                "aggregation": "sum"
            },
            {
                "uniqueName": "Net Sales",
                "aggregation": "sum"
            },
            {
                "uniqueName": "Gross Sales",
                "formula": "sum(\"Net Sales\") + sum(\"Discount\")",
                "caption": "Gross Sales"
            },
            {
                "uniqueName": "Gross Profit Margin",
                "formula": "(sum(\"Revenue\") - sum(\"Net Sales\") ) / sum(\"Revenue\")",
                "caption": "Gross Profit Margin",
                "format": "percentages_formatting"
            },
            {
                "uniqueName": "Burn Rate",
                "aggregation": "average",
                "active": false,
                "format": "percentages_formatting"
            }
        ]
    },
    "conditions": [{
            "formula": "#value > 6000",
            "measure": "Revenue",
            "format": {
                "backgroundColor": "#00A45A",
                "color": "#FFFFFF",
                "fontFamily": "Arial",
                "fontSize": "12px"
            }
        },
        {
            "formula": "#value > 1000",
            "measure": "Discount",
            "format": {
                "backgroundColor": "#df3800",
                "color": "#FFFFFF",
                "fontFamily": "Arial",
                "fontSize": "12px"
            }
        }
    ],
    "formats": [{
        "name": "percentages_formatting",
        "decimalPlaces": 2,
        "isPercent": true
    }]
};

return <div className="App">
            <FlexmonsterReact.Pivot ref={pivot_ref} toolbar={true} width="100%" report={pivot_report} reportcomplete={onReportComplete}  reportchange={syncFilters}/>
            <FlexmonsterReact.Pivot ref={column_chart_ref} toolbar={false} width="100%" report={report_column_chart}/>
            <FlexmonsterReact.Pivot ref={line_chart_ref} toolbar={false} width="100%" report={report_line_chart}/>
            <FlexmonsterReact.Pivot ref={line_chart2_ref} toolbar={false} width="100%" report={report_line_chart_2}/>
            <FlexmonsterReact.Pivot ref={line_chart3_ref} toolbar={false} width="100%" report={report_line_chart_3}/>
           </div>;

Each report contains valuable information about the data source, fields on the grid, formatting, filtering, sorting, and the layout's structure. As you may notice, it has a neat JSON structure that is easy to digest.

After we’ve initialized all the instances of Flexmonster, as a bonus, I suggest making them interconnected. We can achieve a real-time interaction between the dashboard’s elements by synchronizing their filters. Let’s implement the following scenario: make all the pivot charts react to changes in the filtering configurations of the pivot table. This can be done easily with the help of the reportchange event and a custom function:

const syncFilters = () => {
    if (!pivot_ref || !column_chart_ref || !line_chart_ref || !line_chart2_ref || !line_chart3_ref) return;
    // apply filters from the pivot table to all the charts
    var hierarchies = pivot_ref.current.flexmonster().getAllHierarchies();
    hierarchies.forEach(function(item) {
        column_chart_ref.current.flexmonster().setFilter(item.uniqueName, pivot_ref.current.flexmonster().getFilter(item.uniqueName));
        line_chart_ref.current.flexmonster().setFilter(item.uniqueName, pivot_ref.current.flexmonster().getFilter(item.uniqueName));
        line_chart2_ref.current.flexmonster().setFilter(item.uniqueName, pivot_ref.current.flexmonster().getFilter(item.uniqueName));
        line_chart3_ref.current.flexmonster().setFilter(item.uniqueName, pivot_ref.current.flexmonster().getFilter(item.uniqueName));
    });
}

You can take a look at how the entire code inside PivotTableHooks.js looks like.

  1. Import PivotTableHooks to App.js and make the router handle the home page:
import React, {Component} from 'react';
import {BrowserRouter as Router, Route} from 'react-router-dom';
import PivotTableHooks from './PivotTableHooks';

class App extends Component {

  render(){
    return (
        <Router>
          <Route path="/" component={PivotTableHooks}/>
        </Router>

    );
  }
}
export default App;

Results

Now it’s time to run our application and see the results in action! Type in npm start in the console and open http://localhost:3000/. As you see, the pivot table and pivot charts are rendered on a single web page. Coupled together, they provide different views of the same data.

The end-users of your app can interact with such embedded analytics to produce insightful reports. Since all the dashboard’s elements are in sync, each time the data is filtered on the grid, it’s filtered in the pivot charts as well.

It's worth noting that the reports can be configured not only with code but also via the UI. Further, they can be saved in the JSON format and exported to PDF, Excel, HTML, and other formats.

Play with code

You can see the full code of the sample project on my GitHub.
To play with a dashboard and explore its functionality, you can test an alternative JavaScript sample that is available on CodePen.

Final thoughts

Today we've killed two birds with one stone - practiced creating an application with React Hooks and empowered the app with a custom embedded reporting solution that is ready to tackle data analysis challenges.

As you could conclude from your own experience, it takes little time to create such an app. To my mind, this is due to the ease of adding the pivot table using hooks. You can write a single import statement and "hook" the reporting functionality into your app in seconds.

This tutorial provides one of the numerous scenarios of working with the component. Alternatively, you can build more complex by making the pivot table retrieve the data from your SQL/NoSQL database, OLAP cube or Elasticsearch - depending on the data source you prefer the most.

Feedback

I’ll be glad to hear your feedback on the tutorial! Any suggestions for improvements are highly appreciated.

Discover more

To deepen your knowledge of React Hooks, I recommend reading an official guide on React Hooks and Hooks at a Glance - an overview for experienced React users. Also, you may like the talks from React Conf 2018 by Sophie Alpert, Dan Abramov, and Ryan Florence.

To take a closer look at the functionality of Flexmonster, I recommend exploring its live demos, tutorials on integration with frameworks and API reference.

Discussion

pic
Editor guide