Single page application in React on ASP.NET Core

Single page application in React on ASP.NET Core

What is React

React is an open-source client-side JavaScript framework for building user interfaces. It is developed by Facebook and used in their own products. It is also used by some other mayor web-sites like Netflix, imgur, Weather Underground and Feedly.

The two main reasons why they developed React were performance and simplicity. To achieve this React moves away from templates and data-binding but uses JavaScript components and a one-way data flow instead. This combined with a Virtual DOM decreases the number of updates to the real DOM and makes the user interfaces more responsive to data changes and user interactions. It this post I describe briefly how to develop an single page application in React on ASP.NET Core.

Creating React components

The React JavaScript Components represent a part of the view that will be rendered. They use JSX to describe the HTML tags needed to render the components on the page. JSX is a JavaScript extension that allows developers to define XML-like tags in their JavaScript code. This extension is not supported by browsers out-of-the-box but a transpiler like Babel is used to covert JSX into standard JavaScript. More about this later in this post.

In this example renders the MainPage component a div tag with some child components. You also see that it passes data to the header by assigning values to the attributes userAuthenticated and userName.

Declaring a style for components is as easy as assigning the style as Json object to the style property of a component in the render method

Similar like we route url’s on server side to specific views we use a router on the client side to map specific urls to a view.

One-way data flow

Components are structured in an hierarchical way and they use two types of data to render the HTML. They received input data (accessed via this.props) from the parent component. And a component can also maintain internal state data (accessed via this.state). The differences are outlined in detail here. When the data of a component changes, the component is rendered again based on the updated data. Properties also support property validation to ensure the data is correct during development.

React-Components

Managing state with Flux and Reflux

To achieve high performance React recommends using a single immutable state with unidirectional data-flow to render your application. This is supported by the Flux architecture and the Redux library.

React-Data-Flow-1

  • API this is the back-end API used for authorization, documentation and real-time data of the vehicles written in ASP.NET Core. This API is accessible over HTTP and web-sockets.
  • Service encapsulates the logic that calls the API or receives push messages from the API over web-sockets. This is a bit different as in most Redux examples but it seems more logic than placing the API calls in the Views or in the Action’s itself. This makes the Actions and Reducers only responsible for state changes. This also makes the the React Components lighter and easier testable because they don’t need to know about the action creators and the dispatcher.
  • The Store holds the single immutable state. This state is composed out of multiple reducers each responsible for a part of the state.

    When the state is constructed or updated each reducer is called to get a part to the state. And these parts are combined into the single immutable application state.
  • Actions are methods that create action objects to update the state. Action objects are simple JavaScript objects that represents what is is or should change in the state. These objects are dispatched to the store in order to update the state.
  • Reducers handle the actions and return the a new version of the state changed according to the received action.
  • Component are are the main views of the application. These views are connected to the global store by the connect method. This ensure that the view is notified when the state has changed. When the state is changed the mapStateToProps() method is invoked. This method transforms the state into the data (props) necessary to render the component.

    {this.props.children}

     

    ); } } MainPage.propTypes = { loggedOn: PropTypes.bool, name: PropTypes.string }; function mapStateToProps(state) { return { loggedOn: state.user.status === userStatus.authenticated, name: state.user.name }; } export default connect(mapStateToProps)(MainPage);

  • Sub-component are declared by component. They are not connected to the store directly but receive their data from the parent document by using the properies. (this.props)

Please have a look at the official Flux and Redux documentation for more detailed infromation about this pattern. In the sample application I diverge a bit from the I encapsulated

RealTimeWeb currently doesn’t support server-side rendering but it will be added in the near future…

Using ES2015

The JavaScript language has improved quit a lot last years and the latest standard includes some really powerful features to create more readable and maintainable code.

ECMAScript 6 is the newest version of the ECMAScript standard. This standard was ratified in June 2015. ES2015 is a significant update to the language, and the first major update to the language since ES5 was standardized in 2009. Implementation of these features in major JavaScript engines is underway now.

Quote taken from the Babel ES2015 page. ES2015 is however not yet supported by most browsers, but that doesn’t prevent us from using the features already. The langue can be used by processing the JavaScript files by the Babel transpiler. This tool convert the ES2015 source code into plain JavaScript understandable by the browsers. We also use this to tranform JSX code into JavaScript.

Here are the 4 most powerful JavaScript features used in the sample application:

  • Modules are now supported at language level by using the import and export statements.
  • By adding arrows functions () => {}, also called lambda functions, JavaScript finally supports the condensed way to declare anonymous functions as supported in most recent language.

    {message}

    ) ));

  • Classes and inheritance are now supported by a class and extends statements. Note that this is still prototype-based inheritance and that it is a different model in comparison to other class-based programming languages.

  • Spread and rest operators (…). Spread and rest operators are used to split and combine arrays or objects. Especially the object spread operator is really powerful because it can be used to clone and extend objects.

For a coprehensive list of the new features take a look at the Babel web-site

Managing JavaScript dependencies

Modern web-application consist of a large part of JavaScript code these days. And whole range of JavaScript libraries are available to use. These libraries are managed by the node package manager (npm). Npm uses a package.json file in the root of the web-project to keep track of the dependencies. This makes it easy to (re)install the necessary JavaScript dependencies by calling npm install from the command line or during the build process.

The main libraries used in RealTimeWeb are:

  • React, the client side library developed by Facebook, for creating a single page application
  • Redux for managing state in the javascript application
  • React bootstrap enabling the usage of the Twitter Bootstrap library from React

Gulp scripts

Gulp is a node.js task runner that supports many plug-ins. It is used to create build tasks and watchers. The most important plug-ins used in the application are Browserify and Babelify. Browserify combines all JavaScripts files into a single downloadable file. And Babelify transpiles ES6/7 and JSX into plain JavaScript to enable the usage of new JS features and syntax.

JavaScript-Files

The main build task preforms following task in sequence:

  • Clean the wwwroot folder. This is the folders that is used by the web-server to respond requests of the static files of the web-application
  • Browserify is used to combine Client/src/app.js and all its dependencies into a single JavaScript file wwwroot/scripts/app.js. Babelify is used to support ES6/7 and JSX features. Some libraries like React and Redux and are excluded from this file and are combined in a different vendor.js file.
  • Browserify is used to combine libraries like React and Redux in a wwwroot/scripts/vendor.js file. This improve the build time of the app.js file drastically. It also improves the load time of the page because these much less frequently changed in comparison to the application files.
  • Static files are copied from Client/statics to wwwroot

Check out Client/tools/build.js for the full gulp script.

Command line tools

Using command-line tools can improve the productivity during development. Here I present you the tools used to build and test the JavaScript application. All tools should be executed from the web-application folder src/Soloco.RealTimeWeb

To build all front-end files files from client to wwwroot folder the gulp build script is executed:

Watch for changes in JS files and build instantly. This is the tool that you will keep open in a console window during development.

Build and copy only application files. This performs a faster build because it doesn’t clean the wwwroot folder and doesn’t build the vendor.js. This can be uses during development

Run all JS tests:

Run all JS tests and watch for changes. You can keep this running in a separated terminal during the development of the JavaScript application and tests.

Using React on ASP.NET Core

Loading the React SPA in a ASP.NET Core view is as easy as including the generated app.js and vendor.js files in the generated HTML file

@*Fork me on GitHub*@

Testing the React application

While developing a React application I found these three kinds of tests really valuable.

  1. Testing of the actions and their effect on the state.
  2. Mapping of the state to component properties.
  3. Rendering of the component. For this we mock the called service by using __Rewire__. Currently this test only verifies that the view is rendered without any errors. While this is already valuable on it’s own, this test can (or should) be completed with assertions of the rendered view.

Next

In the next post I describe how I implemented authentication via OAuth for the React application.

Source code

The source code of the application can be found on github:

https://github.com/tim-cools/RealTimeWeb.NET

Warning!

The application is still work in progress and new features will be added in the next following weeks…

Some of the technologies and frameworks used in this application are pre-release and most likely to change. Currently it is based on RC1 of .NET Core. I try to update the code as soon as possible whenever the final version is released. Ping me on Twitter if you have questions or issues.


RealTimeWeb.NET Blog Posts

This post is part of a blog post series about RealTimeWeb.NET application.

  1. RealTimeWeb.NET – A real time ASP.NET Core application
  2. Getting started with RealTimeWeb.NET
  3. RealTimeWeb.NET Front-end
    1. Creating an ASP.NET Core web application
    2. Single page application in React on ASP.NET Core
    3. React Authentication on ASP.NET Core with OAuth and Identity
    4. Real-time data pushed by web-sockets (SignalR) on ASP.NET Core
    5. Server-side rendering
  4. Real-time back-end
  5. Operations
  6. ...

1 reply
  1. Javier
    Javier says:

    I congratulate you for the excellent work, very clear thank you very much for the information !! regards

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *