65.9K
CodeProject 正在变化。 阅读更多。
Home

几分钟内使用 ReactiveX.Net 构建实时 React 图表

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (5投票s)

2017年4月13日

Apache

3分钟阅读

viewsIcon

16999

如何轻松地将来自跨平台 .NET 后端的异步实时数据流添加到您的 React Web 应用程序

引言

如果您曾经需要处理异步数据流,您可能已经使用过或至少听说过 ReactiveX,这是一个用于反应式编程的库,它提供了强大的 API 来将数据流转换为可观察序列,可以订阅和操作这些序列。 但它与常规事件驱动方法的区别在于,它能够从多个其他可观察序列中组合新的数据流,您可以灵活地组合、过滤或转换这些数据流。

我将演示如何利用它和我自己的库 dotNetify-React 来使异步实时 Web 应用程序的实现变得非常简单。 这是我们将要构建的内容的输出

它是一个 Web 浏览器上的实时图表,由异步数据流提供数据,该数据流本身由两个不同的数据流组成:一个用于正弦波信号,另一个用于其振幅。

以下步骤使用 Facebook 的 create-react-app 样板来生成 Web 应用程序,并使用 .NET Core SDK 运行后端。 您需要先安装它们。

如果您只想拉取源代码,请访问 Github dotnetify-react-demo。 还有一个在 Visual Studio 2017 上运行的版本,位于 dotnetify-react-demo-vs2017

前端

我们将从创建应用程序外壳并安装所需的库开始

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

(我坚持使用旧版本的图表库,因为自那时以来 API 已经改变,我对它们还不熟悉。)

添加组件 /src/LiveChart.jsx,它将呈现图表

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>
      );
   }
}

此组件最初将使用来自 *react-chartjs* 的条形图组件以及一个空数据集来呈现图表。 一旦通过 *dotNetify* 建立与后端的连接,该组件将收到对 `this.state.NextValue` 的实时更新,这反过来会导致图表使用新的数据集值重新呈现。

接下来,替换默认的 /src/App.js 以呈现我们的组件

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

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

后端

有了前端之后,我们现在添加 .NET Core 后端部分。 首先创建一个默认的 ASP.NET Core Web 项目并安装所需的包

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

打开 *package.json* 并添加以下行,以将 Node 开发服务器未处理的请求重定向到 .NET Core 服务器

"proxy": "https://:5000/",

仍然在 *package.json* 中,修改调用 `react-scripts` 的行,以使用 `concurrently` 库启动 Node 和 .NET Core 服务器

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

接下来,添加类 LiveChart.cs,它将为前端组件提供实时更新

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();
   }
}

这个类背后的想法是生成一个由两个其他流组成的数据流:一个用于正弦波信号,另一个用于数字迭代以产生波动的幅度。 为了创建流,我们使用 *Rx* API `Observable.Interval` 在时间间隔内发出一个整数序列,然后将其进一步投影到所需的序列中。 然后将这两个流与 `Observable.Zip` 组合成一个单一的流,我们的类实例会订阅该流。

当新数据可用时,我们使用 *dotNetify* API `Changed` 和 `PushUpdates` 将数据发送到前端组件以更新其本地状态。 实际的通信是通过 *SignalR* 完成的,它将在可用时使用 `WebSocket`。 但我们不必担心它,因为它已经被抽象掉了。

接下来,在 *Startup.cs* 中配置 *dotNetify* 和 *SignalR*

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");
         });
      }
   }
}

最后,构建并运行应用程序

dotnet build
npm start

摘要

就是这样。 您可以在几分钟内快速构建一个异步实时 Web 应用程序。 尽管这是一个有些牵强的例子,但我希望它仍然可以用来展示这种技术是多么强大。

在现实世界的场景中,Web 客户端可能正在等待多个后端微服务,这些微服务的异步输出需要链接在一起才能生成最终结果。 使用 *ReactiveX* 和 *dotNetify* 的组合将大大降低代码的复杂性并节省您的时间和精力。

© . All rights reserved.