Building React Applications in C#: A Beginners Guide


In the sea of alternative javascript stacks lies a hidden C# to javascript transpiler that you actually can rely on and use in production. Ofcourse I am talking about Bridge.NET, a compiler and a set of tools to build javascript applications using C#.

Writing C# for the front-end is a huge win. First of all, you can use all of C# as Bridge supports features C# 6, think Linq, async/await, generic collections, reflection etc. Second, you can share client models (Poco’s) with the server and sometimes even share business logic, mostly the validation code for these models.

In this article, we will learn how to make React apps in C# using Bridge. If you are not familiar with React nor with Bridge, this article is for you. I will explain the principles as we progress. I only assume you are familiar with C#. Ofcourse, to really understand React patterns you have to play around and explore with React to eventaully build something yourself.

React + C# = ❤️

C# makes a perfect fit for developing React applications. Using C# Poco’s and the type system to model the properties (props) and the state of you components is very convenient and helps you think clearly of the responsibilities of the different parts of your application before actually implementing these parts.

React with Bridge.NET

Because React is a Javascript library, you can’t just use it right away from C#. You will need a binding library. A binding library is a C#-library written in such a way, that when you call C# code, it translates as calls to existing javascript functions and other blocks of code.

Fortunately, you don’t have to write your own binding library, there is already one for you. Bridge.React, a library for writing React applications in idiomatic C#. An in-depth introduction on the implementation and usage of the library can be found here from the author of the library himself.

Building from the ground up

To start from scratch, let’s spin up a “Hello world” example and work our way to the Todo app. open your Visual Studio and create a new Class Library project, I called it “ReactTodo”

You will get a default class library project with one class called Class1.cs . Rename this to Program.cs as this will be the starting point of your application. Turn your code into this:

“Wait a second, this looks more like a Console application, not a Class library, what’s up with that?” Well, because this will be compiled to javascript, it needs a starting point to run when the browser loads the generated scripts. Bridge will detect that this static void Main() method is the where the application is starting from.

To actually start using Bridge, you only need to install the Bridge nuget package. Either search for it from the Nuget Package Manager or just install it from Packege Manager Console by running:

Install-Package Bridge

When you have installed it, a directory is added to your project called “Bridge” that has:

  • output directory: this is where your javascript files get generated
  • www: this is where your demo.html file is located, this file in turn, will reference the generated script using a relative path.
  • bridge.json: a global configuation file for the bridge compiler. All the options are documented here.

Without futhur ado, build the project and view your demo.html in the browser to see this:

Great, the javascript code is working. This is a specialized console from Bridge that is rendered on the page. If you look at your browser console, you should also see the same message printed. In your demo.html file, see the scripts being referenced:

<script src="../output/bridge.min.js"></script>
<script src="../output/ReactTodo.js"></script>

The bridge.min.js file is the core javascript library of bridge. This library has most the functionality mscorlib implemented and all the scripts generated with Bridge depend on it. The second script is just the script generated from your code:

The code is quite readable too.

Interaction with the DOM

Lets make a button that, when clicked, an alert message shows up. This is quite simple, first you will have to start using Bridge.Html5; and then turn the Main() method into the following:

Rebuild the project and refresh the demo.html page, now when you click the button, an alert is shown:

A different programming model

In the previous example, we built a button Node, attached event handlers to it and added it on the browser screen. That went a bit “manual”. For a button, this is fine, but when an application becomes larger and larger, it becomes harder to manage control interactions and their data. Here comes React into play, it provides a programming model, a way to build your application, such that when it becomes larger, the complexity stays managable (while keeping you sane).

“View” as a function of data

The main principle of React is that you build your user interface, also known as: the view, as a function of data. Data comes in, view comes out. In C# code, it looks like this:

This function represents building the view:

data => <div>{data}</div>

the function depends on the parameter data . For example, if data = hello Mike you would get:

<div>hello Mike</div>

“So this react thing is like a templating engine?” You might ask. Well, not exactly. React is not using a custom templating language with some special syntax to build html, but rather it lets you use javascript to build an xml structure or tree as a representation of the html that it is going to build (because html itself has a hirarchical structure of an xml tree). From this representation that you are building in code, React will take care of creating the actual html nodes that are rendered and viewed in the browser. The browser uses the so-called document object model (or DOM for short) to represent the nodes and controls it renders on the screen. Because React only works the representation of the DOM, that representation (the xml-like tree) is called a virtual DOM.

React: Hello World

React is javascript library and in order to use it, you need to reference the sources from your web page, demo.html in our case. You can reference the libraries directly from cdn services, or download the files on your machine and refernce them locally. I will use cdn services. External references like React javascript files are always referenced before your Bridge-generated scripts because if the scripts need to call React, React will have to be defined first, demo.html becomes:

Great, we have the external refernces set up. Also note that I added a div tag in the body with an id of “app”. This node will be the placeholder for the React application that we will be building.

Back to our React binding, the Bridge.React library. You can install this library from Nuget too:

Install-Package Bridge.React

After you have installed this, you can start using Bridge.React; and call code from there. Now to start with a minimal example, let us create the function called View that generates a div tag, my full Program.cs file looks now like this:

Notice a couple of things, the return type of the function View is a ReactElement. Every virtual node is a ReactElement. You use the DOM class to build these virtual nodes.

To initialize React, you have to tell it where the virtual nodes have to be created. In our case, we are telling React to mount the virtual nodes on the element of id = “app” (the div tag we added earlier to our page). When this code is run, the node <div id="root"></div> will be replaced with <div>Hello Mike</div> .

If you build your project now and refreshed the page, you wouldn’t anything just yet. When you are using code from Bridge.React, this library also gets compiled so you have to reference the generated script too:

Now you can build and refresh your page to see this:

Nice, React is up and running! Let’s try nesting these virtual nodes. To build something like the following:

Your View function becomes:

Will generate:

Because the DOM.P function was used within the DOM.Div function, we call the DOM.P a child component of DOM.Div. This time we were using a different overload of the Div function, the first parameter is an empty attributes object, this object defines attributes, properties and event handlers of the rendered elements. Lets create a button now with an event handler:

The functions Div, Button and others within the DOM class are called the “primitives” of React because you can build bigger views with them and use those to build even bigger views and components. Usually the primives will have either one paramter, that is a child element or the first parameter is the attributes and the rest is a list of child elements. Build and refresh:

In the previous examples, we were using a function to build the view, we give it data and out comes a ReactElement that we attach to a DOM node. Such views that only depend on data being passed are called “Stateless views” or “Stateless components”. Stateless because they don’t manage data explicitly. A text box (input element) for example manages the state of the text internally (implicitly).

Stateful Components with React

A Stateful React component consists of these main parts:

  • Properties (props): are responsible for communicating with parent and child components (more on this later)
  • State: is what the component keeps track of during interaction with the user.
  • A Render function that returns a view based on the props passed and the current state of the component.

Consequently, when creating a component A, you ask yourself these questions:

  • What data do I need passed from the parent component to component A? (the props)
  • What data do I want to keep track of when the user is interacting with the component? (the state)
  • What initial data does my component need before any interaction? (the initial state)

Consider the following piece of user interface:

“What data do I need passed from the parent component to component A?” Well, in this case there is no parent component so no props needed.

“What data do I want to keep track of when the user is interacting with the component?” When the user is typing in the input element, the text is echoed another element, so obviously, I want to keep track of the text from input element.

“What initial data does my component need before any interaction?” Initial state will be an empty text for the input.

Pro Tip: When adding a class to your project with “Add New Item”, do not add a class but rather an empty code file. If you add a class, it will automatically reference the original mscorlib to the project which makes Bridge unhappy

Stateful components are built using C# classes. Such classes will inherit from the base class Component<TProps, TState> where TProps is the type of the props and TState is type of the state. Let me show you the code of the above component, I call it MessageEcho, then we dissect the parts of it:

Things to notice:

  • The props and state are defined as nested classes, you could define them somewhere and call them MessageEchoProps and MessageEchoState but this seems to be a clean solution when you have many components.
  • The body of the constructor must stay empty as this is not how the component is initialized. When you need to run code when the component is initialized, you override the ComponentDidMount method.
  • The base class constructor is called using a default empty props object because this component doesn’t need props. If we had props, we put them in the constructor of MessageEcho and propagate the parameter to base class.
  • The Render method is where you put your view elements.

Take a closer look at the Render method. You will see that the text within the DOM.H1 element is the the TextInput from the current state. When the state changes, the Render method is called again and the elements are re-rendered with the new state. But how is the state changing? Well, through the event handler of the input element. When you start typing into the input element, the value of the text input updates the TextInput property of the state and the SetState method is called. When SetState is called, React will re-render the component with the new data.

To use this component, you change your Main() method to:

Build and refresh to use the component.

Parent-Child data communication

A lot of the time, you build components that are made out of smaller components, also known as: child components. Every one of these child component manages it’s state internally. This means that a parent component cannot access the state of a child component nor it should, parent components deal with child components as black boxes. To make communication possible, child components would have to expose parts of their state, but only indirectly. Let me illustrate by modifing our MessageEcho component to expose the TextInput property of the state to “the outside world”. This is where the Props come into play.

The outside world would pass in functions in the props, these functions will be called from inside the component.

First of all, add an Action<string> to your props, call it “OnAdded”`:

Now that we are using props, the constructor of MessageEcho must take a MessageEcho.Props parameter that will be propagated to the base class:

Now, instead of just writing the text on the h1 tag, add a button, that when clicked, will call the OnAdded function passing the TextInput from the current state:

Notice the OnClick event handler with the button: first we make sure the property TextInput is not null or whitespace, then we invoke the OnAdded method from the props passing in the TextInput property. “But where is the implementation of OnAdded is coming from?” From the outside when a consumer of the component is instantiating it. In our case, we are instantiating the component in the Main() method so that’s where we put the implementation when we are passing the Props:

Will result in:

We have succesfully managed to expose a part of state, the input text, to the outside world, in this case, just to the browser alert message. This technique of using functions this way is little inversion of control mechanism. Now let us see what happens when you have parent component using the MessageEcho component. Let’s make something like this:

This will be a parent component using, I call it MessageLogger using the MessageEcho as a child component:

Then use the MessageLogger to initialize the app:

The End

That was it for today, hopefully you learnt something from this and had some fun along the way, I sure did! The code presented here is published on github in this repo. I think at this point, you know just enough to build your own thing. If you liked this article, hit that 💚 button and share!