How to add asynchronous, real-time data stream from a cross-platform .NET back-end to your React web app with much less effort.
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 of other observable sequences, which you can combine, filter, or transform with great flexibility.
1.1.1 React 是什么React IS A JAVASCRIPT LIBRARY FOR BUILDING USER INTERFACES 来自:React 官方网站狭义来讲 React 是 Facebook 内部开源出来的一个前端 UI 开发框架,广义来讲 React 不仅仅是 js 框架. TypeScript 1.6 adds support for JSX/React syntax, allowing React developers to mix TypeScript code and JSX HTML-like syntax using the new.tsx file extension. In addition to compiler support, you can use the new mixed syntax in Sublime Text, Visual Studio Code, or Visual Studio.
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:
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.
We will start by creating the app shell and installing the required libraries:
(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:
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:
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:
Open package.json
and add the following line to redirect requests that are unhandled by the Node dev server to the .NET Core server:
Still inpackage.json
, modify the line that calls the react-scripts
to use the concurrently library to start both Node and .NET Core server:
Next, add the class LiveChart.cs
that will provide the real-time update to the front-end component:
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 RxAPIObservable.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:
Finally, build and run the application:
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.
By default, create-react-app
comes without scss
enabled. We are going to create a workflow to enable watching, compiling and exporting .scss
files to import
them as .css
files into our components — all without having to eject
.
create-react-app
installed.node
installed.Being able to integrate a streamlined workflow that converts .scss
files to .css
without our direct involvement will make us more productive and efficient in our React development.
Let's start by creating a sample react application:
Then, we first need to install the command-line interface for Sass as follows:
yarn:
npm:
After the package is installed, in our package.json
, we are going to create a script to compile .scss
to .css
:
The script
build-css
takes the .scss
files present within the src
folder and subfolders and compiles them to .css
files. The .css
file will be present in the same location as the original .scss
file. Without having to think about any other paths, it becomes easy to import the .css
file in the components that we are styling.
Next, we are going to create a script to run build-css
to compile any existing files into .css
but also to keep watching the src
folder for changes — as in changes to the content of existing .scss
files or the addition of new ones:
Our initial package.json
would look like this:
Let's test these scripts. Within src
, create test.scss
with the following content:
Run your React app and notice that there are no changes yet. At this point, we cannot import the styles of test.scss
into any of our components yet since we need its .css
version. Let's run the build-css
command manually:
yarn:
npm:
Depending on your development environment, you may see the .css
file nested within the .scss
file or adjacent to it. I am using WebStorm and my .css
file is nested. If you are using Visual Studio Code, for example, the file is adjacent.
We can now import test.css
into the App
component. Open App.js
and add the following import:
Save App.js
and now your React app should have a blinding red background. Let's change it to a softer color. Go back to test.scss
and change its contents to:
Save test.scss
and look at the browser. Nothing happened. That's because we have not run build-css
manually. Run the script once again and the background color should change. Running this script manually is very tedious and that's why we created that watch-css
script. Let's run our watch script to see its time-savings benefits:
yarn:
npm:
Let's go back to test.scss
and change the background color to lightblue
. Save it. This time the browser reloaded and the new background color is being displayed.
Let's add a new file to test that our watch-css
script is recognizing new .scss
sources. Create another-test.scss
within the src
folder with the following content:
Save the file. You won't see any changes in the browser (because the file has not been imported anywhere) but you will see that another-test.css
has been created. Let's import it into App.js
and then we should see the text color in the browser change to navy.
We have achieved the task of automating the compilation of .scss
into .css
files that we can import into our components for styling; however, as of now, we would have to run watch-css
manually every time we start the project. What we are going to do next is to run this script when we start the project.
We are going to rename the current start
script to start-react
.
From
To
Do not forget to add commas at the end of every JSON property when there is more than one property — if you do, it would break your package.json
file.
We are going to recreate start
as a script that runs both start-react
and watch-css
in parallel. Out of the box, npm
doesn't offer that functionality, but we can use a handy package named npm-run-all
that exactly does that for us.
Install npm-run-all
:
yarn:
npm:
Once the package is installed, we create start
as follows:
The -p
flag signals npm-run-all
to run the commands that follow in parallel.
Stop your application if it's running and rerun it again:
yarn:
npm:
Once again, go to test.scss
and change the background color to lightseagreen
. Save the file. This time the browser updates and showcases the new background color.
One last important step that we need to take is to update our build
script. When we build our project, we need to ensure that any .scss
file is compiled. We are going to rename the existing build
to build-react
and then create new script logic for build
— just as we did with start
:
This time around, we want to build-css
first and then build-react
. Using npm-run-all
we can do that by specifying the -s
flag which signals it to run the following commands in sequence.
Your final package.json
should look like this:
You can save this package.json
somewhere else and simply copy and paste its contents into the body of the package.json
of new projects you start.
We were able to bring scss
power into the context of create-react-app
without resorting to eject
by using npm
scripts and the npm-run-all
package. As always, I hope that you enjoyed this blog post. If you want to share improvements or comments on this process of handling scss
, feel free to reach out to me on Twitter, @getDanArias. Thanks for reading!