Click here to Skip to main content
15,881,882 members
Articles / Web Development / React
Tip/Trick

Real-Time React Chart with ReactiveX.Net in Minutes

Rate me:
Please Sign up or sign in to vote.
4.88/5 (5 votes)
12 Apr 2017Apache3 min read 15.6K   23   2
How to add asynchronous, real-time data stream from a cross-platform .NET back-end to your React web app without much effort

Introduction

If you ever have to deal with asynchronous data streams, you probably have used or at least heard of ReactiveX, a library for reactive programming which offers powerful APIs to transform data streams into observable sequences that can be subscribed to and acted upon. But what sets it apart from the regular event-driven approach is the capability to compose new data streams out of multiple other observable sequences, which you can combine, filter, or transform with great flexibility.

I will demonstrate how you can leverage this and my own library dotNetify-React to make an asynchronous real-time web application fairly trivial to implement. Here is the output of what we will be building:

Image 1

It is a live chart on a web browser, fed by an asynchronous data stream that is itself composed of two different data streams; one for the sine wave signal and the other its amplitude.

The following steps use the create-react-app boilerplate from Facebook to generate the web app, and .NET Core SDK to run the back-end. You will need to install them first.

If you just want to pull the source code, go to Github dotnetify-react-demo. There is also a version that runs on Visual Studio 2017 at dotnetify-react-demo-vs2017.

Front-End

We will start by creating the app shell and installing the required libraries:

create-react-app livechart
cd livechart
npm install dotnetify --save
npm install chart.js@1.1.1 --save
npm install react-chartjs@0.8.0 --save
npm install concurrently --save-dev

(I keep to an older version of the chart library because the APIs have changed since and I‘m not familiar with them yet.)

Add the component /src/LiveChart.jsx that will render the chart:

JavaScript
import React from 'react';
import dotnetify from 'dotnetify';
import { Bar } from 'react-chartjs';

export default class LiveChart extends React.Component {
   constructor(props) {
      super(props);
      dotnetify.react.connect("LiveChart", this);
      this.state = {};

      this.chartData = {
         labels: Array(10).fill(""),
         datasets: [{
            data: Array(10),
            fillColor: 'rgba(75, 192, 192, 0.2)',
            strokeColor: 'rgba(75, 192, 192, 1)'
         }]
      };
      this.chartOptions = { 
         responsive: true, 
         scaleOverride: true, 
         scaleSteps: 5, 
         scaleStepWidth: 10 
      };
      this.updateChart = value => {
            this.chartData.datasets[0].data.shift();
            this.chartData.datasets[0].data.push(value);
      };
   }
   render() {
      return (
         <Bar data={this.chartData} options={this.chartOptions}>
            {this.updateChart(this.state.NextValue)}
         </Bar>
      );
   }
}

This component will initially render a bar chart component from react-chartjs with an empty data set. As soon as the connection to the back-end through dotNetify occurs, the component will be receiving real-time update to this.state.NextValue , which in turn causes the chart to re-render with the new data set value.

Next, replace the default /src/App.js to render our component:

JavaScript
import React, { Component } from 'react';
import LiveChart from './LiveChart';

export default class App extends Component {
  render() {
    return <LiveChart />
  }
}

Back-End

With the front-end in place, we now add the .NET Core back-end piece. Start by creating a default ASP.NET Core web project and installing the required packages:

dotnet new web
dotnet add package DotNetify.SignalR --version 2.1.0-pre
dotnet add package System.Reactive
dotnet restore

Open package.json and add the following line to redirect requests that are unhandled by the Node dev server to the .NET Core server:

JavaScript
"proxy": "http://localhost:5000/",

Still in package.json, modify the line that calls the react-scripts to use the concurrently library to start both Node and .NET Core server:

JavaScript
"start": "concurrently \"react-scripts start\" 
\"dotnet run\" --kill-others",

Next, add the class LiveChart.cs that will provide the real-time update to the front-end component:

C#
using System;
using System.Reactive.Linq;

namespace livechart
{
   public class LiveChart : DotNetify.BaseVM
   {
      private IDisposable _subscription;
      public int NextValue { get; set; }

      public LiveChart()
      {
         var sine = Observable
            .Interval(TimeSpan.FromMilliseconds(100))
            .Select(t => Math.Sin(2 * Math.PI * .06 * t));

         var amp = Observable
            .Interval(TimeSpan.FromMilliseconds(100))
            .Select(a => a % 50 + 1);

        _subscription = Observable
            .Zip(sine, amp, (s, a) => (int) Math.Abs( s * a))
            .Subscribe(value =>
            {
               NextValue = value;
               Changed(nameof(NextValue));
               PushUpdates();
            });
      }

      public override void Dispose() => _subscription.Dispose();
   }
}

The idea behind this class is to produce a data stream that’s composed of two other streams: one for the sine wave signal, the other an iteration of numbers to make a fluctuating amplitude. To create the streams, we use the Rx API Observable.Interval to emit a sequence of integers in a time interval, which is then further projected into the desired sequence. The two streams are then combined with Observable.Zip into a single stream, which is subscribed to by our class instance.

When new data becomes available, we use the dotNetify API Changed and PushUpdates to send the data to the front-end component to update its local state. The actual communication is done through SignalR, which will use WebSocket when available. But we don’t have to worry about it, since it’s already abstracted away.

Next, configure dotNetify and SignalR in the Startup.cs:

C#
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using DotNetify;

namespace livechart
{
   public class Startup
   {
      public void ConfigureServices(IServiceCollection services)
      {
         services.AddMemoryCache();
         services.AddSignalR();
         services.AddDotNetify();
      }
      public void Configure(IApplicationBuilder app)
      {
         app.UseWebSockets();
         app.UseSignalR();
         app.UseDotNetify();
         app.Run(async (context) =>
         {
            await context.Response.WriteAsync("LiveChart server");
         });
      }
   }
}

Finally, build and run the application:

dotnet build
npm start

Summary

And, that’s it. An asynchronous real-time web app that you can quickly build in minutes. Although somewhat a contrived example, I hope it still serves to illustrate how powerful this technique can be.

In a real-world scenario, the web client could be waiting for multiple back-end microservices whose asynchronous outputs need to be chained together to produce the final result. The usage of ReactiveX and dotNetify combo will significantly reduce the code complexity and save you time and effort.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
United States United States
Full-stack s/w engineer, open source author.

Comments and Discussions

 
QuestionNice chart apps Pin
Mou_kol7-Jun-17 22:37
Mou_kol7-Jun-17 22:37 
QuestionDifference between Angular and React Pin
Tridip Bhattacharjee12-Apr-17 22:12
professionalTridip Bhattacharjee12-Apr-17 22:12 
AnswerRe: Difference between Angular and React Pin
dsuryd13-Apr-17 4:45
dsuryd13-Apr-17 4:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.