Skip to Content

Integrate Charts and Conditional Rendering

test
0 %
Integrate Charts and Conditional Rendering
Details

Integrate Charts and Conditional Rendering

2020-01-17
Beginner
20 min.
Display data in charts using UI5 Web Components for React.

You will learn

  • How to install and import charts
  • Learn about charts in UI5 web components
  • How to add dynamic rendering

UI5 Web Components for React also comes with a chart library. In this tutorial, you will integrate two chart types and add data to them. Also you will learn how to conditionally render components, and how React handles updates to the DOM and single components.


Step 1: Install module and import charts
  1. Install the chart library of UI5 Web Components for React.

     npm install @ui5/webcomponents-react-charts --save
    
  2. Then, import LineChart and BarChart into MyApp.jsx.

    import { BarChart, LineChart } from "@ui5/webcomponents-react-charts";
    
Log on to answer question
Step 2: Add charts to Card component
  1. Start with the LineChart and add it underneath the Text component.

    <Text style={spacing.sapUiContentPadding}>
      This is the content area of the Card
    </Text>
    <LineChart />
    

    Well, that didn’t change much, didn’t it? It’s because the chart didn’t receive any data, and therefore the content is empty.

  2. Add data and corresponding labels to your component (right above the return statement).

    const datasets = [{
        label: "Stock Price",
        data: [65, 59, 80, 81, 56, 55, 40]
    }];
    const labels = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July"
    ];
    
  3. Now add datasets and labels to your LineChart components.

    <LineChart datasets={datasets} labels={labels} />
    

    Congratulation, you implemented your first Chart component.

    LineChart
  4. Add a BarChart to the Card.

    We want the same data just with a different representation, therefore you can use the same labels and datasets as you did with the LineChart.

    <BarChart datasets={datasets} labels={labels} />
    

    Two charts are rendered now with equal datasets but different representation.

Your MyApp.jsx component should look like this:

import React from "react";
import { Card, Text } from "@ui5/webcomponents-react";
import { spacing } from "@ui5/webcomponents-react-base";
import { BarChart, LineChart } from "@ui5/webcomponents-react-charts";

export function MyApp() {
    const handleHeaderClick = () => {
        alert("Header clicked");
    };
    const datasets = [{
        label: "Stock Price",
        data: [65, 59, 80, 81, 56, 55, 40]
    }];
    const labels = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July"
    ];
    return (
        <div>
            <Card
                heading="Card"
                style={{ width: "300px" }}
                headerInteractive
                onHeaderClick={handleHeaderClick} >
                <Text style={spacing.sapUiContentPadding}>
                    This is the content area of the Card
                </Text>
                <LineChart datasets={datasets} labels={labels} />
                <BarChart datasets={datasets} labels={labels} />
            </Card>
        </div>
    );
}
Log on to answer question
Step 3: Add conditional rendering

Two charts in one Card is a bit too much, don’t you think? It would be nicer if the charts could be toggled by clicking on the header. Let’s implement that!

  1. First add a state. It should control which chart is going to be rendered.
    Use the State Hook logic to implement the state and set "lineChart" as default value. Don’t forget to import useState from React, otherwise you will get an error.

    • Import the useState function in the header of the MyApp.jsx file (replace the current import of React).

        import React, { useState } from "react";
      
    • Use the useState function in the right after you start to define the MyApp function (before the click handler).

        const [toggleCharts, setToggleCharts] = useState("lineChart");
      
  2. By clicking on the Card header the state should be set corresponding to the chart which should be displayed.

    Rewrite your handleHeaderClick function so it will handle this logic.

    const handleHeaderClick = () => {
      if (toggleCharts === "lineChart") {
        setToggleCharts("barChart");
      } else {
        setToggleCharts("lineChart");
      }
    };
    
  3. To only render the current chart, add the following lines to the render of the component:

    <Card
        heading="Card"
        style={{ width: "300px" }}
        headerInteractive
        onHeaderClick={handleHeaderClick}>
        <Text style={spacing.sapUiContentPadding}>
            This is the content area of the Card
        </Text>
        {toggleCharts === "lineChart" ? (
            <LineChart datasets={datasets} labels={labels} />
        ) : (
             <BarChart datasets={datasets} labels={labels} />
         )}
    </Card>
    

    Done! Now you can toggle between charts by clicking on the header of the Card.

  4. You can further improve your Card component by using the avatar prop and adding an Icon to it.

    Add the following import to your component:

    import { Card, Text, Icon } from "@ui5/webcomponents-react";
    

    And the avatar prop, which receives an Icon as value, to the Card component:

    <Card
      avatar={<Icon name="line-chart" />}
      ...
    </Card>
    

    To reduce bundle size, Icons need to be imported manually. As we used a line-chart add this to your imports.

    import '@ui5/webcomponents-icons/dist/icons/line-chart.js';
    

    The Icons should also be conditionally rendered. Luckily this is easy. First add the bar-chart import:

    import '@ui5/webcomponents-icons/dist/icons/horizontal-bar-chart.js';
    

    Then change the name prop of the Icon to the following:

    <Card
       avatar={ <Icon name={ toggleCharts === "lineChart" ? "line-chart" : "horizontal-bar-chart" } /> }
       ...
     >
    

    Now the Card also changes the Icon by clicking on the header.

    LineChart

If something went wrong you can compare your component to this code snippet:

import React, { useState } from "react";
import { Card, Text, Icon } from "@ui5/webcomponents-react";
import { spacing } from "@ui5/webcomponents-react-base";
import { BarChart, LineChart } from "@ui5/webcomponents-react-charts";
import '@ui5/webcomponents-icons/dist/icons/line-chart.js';
import '@ui5/webcomponents-icons/dist/icons/horizontal-bar-chart.js';

export function MyApp() {
    const [toggleCharts, setToggleCharts] = useState("lineChart");
    const handleHeaderClick = () => {
        if (toggleCharts === "lineChart") {
            setToggleCharts("barChart");
        } else {
            setToggleCharts("lineChart");
        }
    };
    const datasets = [{
        label: "Stock Price",
        data: [65, 59, 80, 81, 56, 55, 40]
    }];
    const labels = [
        "January",
        "February",
        "March",
        "April",
        "May",
        "June",
        "July"
    ];
    return (
        <div>
            <Card
                avatar={<Icon name={toggleCharts === 'lineChart' ? "line-chart": "horizontal-bar-chart"} />}
                heading="Card"
                style={{ width: "300px" }}
                headerInteractive
                onHeaderClick={handleHeaderClick}>
                <Text style={spacing.sapUiContentPadding}>
                    This is the content area of the Card
                </Text>
                {toggleCharts === "lineChart" ? (
                    <LineChart datasets={datasets} labels={labels} />
                ) : (
                    <BarChart datasets={datasets} labels={labels} />
                )}
            </Card>
        </div>
    );
}
Would it be possible to switch between more than two charts by adding some more code?
×
Step 4: Update a component in React - Loading Indicator

One of the main advantages of React is how UI updates are handled. React will only re-render the component if the state of the component has changed. So it will not update the whole UI, but only the component that is affected by changes.

  1. In order to demonstrate this behavior, add a new state (right after the definition of the previous state).

      const [loading, setLoading] = useState(false);
    
  2. Then edit your handleHeaderClick function like this:

    const handleHeaderClick = () => {
        if (toggleCharts === "lineChart") {
          setLoading(true);
          setTimeout(() => {
            setLoading(false);
            setToggleCharts("barChart");
          }, 2000);
        } else {
          setLoading(true);
          setTimeout(() => {
            setLoading(false);
            setToggleCharts("lineChart");
          }, 2000);
        }
    };
    
  3. Add loading to both of your charts.

     <LineChart datasets={datasets} labels={labels} loading={loading} />
    
     <BarChart datasets={datasets} labels={labels} loading={loading} />
    

This updates the component every time you switch between charts and simulates a data call.

As you can see, only the component affected by the state is updated, and the rest stays the same. If you’re working with data, you most probably will need a loading indicator. All UI5 web components that are able to display data have a loading prop and therefore also a loading indicator.

If a prop of a component changes, will the component be updated?
×
Step 5: Add dynamic header and text

To make your Card look cleaner and to give the user the information that the header is clickable, you can add some logic to your component.

  1. Add a dynamic content Text

    The content text is not really informative. Let’s change that and display the type of the chart. Add the following constants to your component (after the event handler):

    const contentTitle = toggleCharts === 'lineChart' ? 'Line Chart' : 'Bar Chart';
    const switchToChart = toggleCharts === 'lineChart' ? 'Bar Chart' : 'Line Chart';
    
  2. Change the title and add a subtitle to your Card

    First change the value of heading to something that explains the content of the Card (e.g., "Stock Price").
    Then add a subtitle prop. Here you can give the users the information that they can switch between charts by clicking the header.

    <Card
         avatar={<Icon name={toggleCharts === 'lineChart' ? "line-chart": "horizontal-bar-chart"} />}
         heading="Stock Price"
         style={{ width: "300px" }}
         headerInteractive
         onHeaderClick={handleHeaderClick}
         subtitle={`Click here to switch to ${switchToChart}`} >
         <Text style={spacing.sapUiContentPadding}>{contentTitle}</Text>
         {toggleCharts === "lineChart" ? (
             <LineChart datasets={datasets} labels={labels} loading={loading} />
         ) : (
             <BarChart datasets={datasets} labels={labels} loading={loading} />
         )}
     </Card>
    
Log on to answer question

Next Steps

Back to top