Productive Rage

Dan's techie ramblings

Removing ALL assembly names in Json.NET TypeNameHandling output

In some cases, it may be desirable to include type name information in Json.NET output but for those type names to not include assembly names.

In my case it's because I have a Shared Project that contains classes that I want to appear in my .NET Core C# server code and in my Bridge.NET client code and this results in the class names existing in assemblies with different names (but there are also other people with their own cases, such as How do I omit the assembly name from the type name while serializing and deserializing in JSON.Net?.

Json.NET has support for customising how the type names are emitted and there is an answer in the Stack Overflow question that I linked just above that points to an article written by the Json.NET author illustrating how to do it. Essentially, you create a custom serialization binder that looks a bit like this:

public sealed class TypeNameAssemblyExcludingSerializationBinder : ISerializationBinder
{
    public static TypeNameAssemblyExcludingSerializationBinder Instance { get; }
        = new TypeNameAssemblyExcludingSerializationBinder();

    private TypeNameAssemblyExcludingSerializationBinder() { }

    public void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        assemblyName = null;
        typeName = serializedType.FullName;
    }

    public Type BindToType(string assemblyName, string typeName)
    {
        // Note: Some additional work may be required here if the assembly name has been removed
        // and you are not loading a type from the current assembly or one of the core libraries
        return Type.GetType(typeName);
    }
}

Then you serialise your content something like this:

var json = JsonConvert.SerializeObject(
    new ExampleClass(123, "Test"),
    new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
        TypeNameHandling = TypeNameHandling.All,
        SerializationBinder = TypeNameAssemblyExcludingSerializationBinder.Instance
    }
);

If the ExampleClass looked like this:

public sealed class ExampleClass
{
    public ExampleClass(int key, string name)
    {
        Key = key;
        Name = name;
    }
    public int Key { get; }
    public string Name { get; }
}

.. and was in a namespace called "Tester" then the resulting JSON would look like this:

{
  "$type": "Tester.ExampleClass",
  "Key": 123,
  "Name": "Test"
}

To make the difference clear, if the custom serialisation binder had not been used (and if the containing assembly was also called "Tester") then the JSON would have looked like this:

{
  "$type": "Tester.ExampleClass, Tester",
  "Key": 123,
  "Name": "Test"
}

So.. problem solved!

Yes?

No.

ISerializationBinder is not applied to generic type parameters

While everything was hunkydory in the example above, there are cases where it isn't. For example, if we wanted to serialise a list of ExampleClass instances then we'd have code like this:

var json = JsonConvert.SerializeObject(
    new List<ExampleClass> { new ExampleClass(123, "Test") },
    new JsonSerializerSettings
    {
        Formatting = Formatting.Indented,
        TypeNameHandling = TypeNameHandling.All,
        SerializationBinder = TypeNameAssemblyExcludingSerializationBinder.Instance
    }
);

.. and the resulting JSON would look like this:

{
  "$type": "System.Collections.Generic.List`1[[Tester.ExampleClass, Tester]]",
  "$values": [
    {
      "$type": "Tester.ExampleClass",
      "Key": 123,
      "Name": "Test"
    }
  ]
}

Without the custom serialisation binder, it would have looked like this:

{
  "$type": "System.Collections.Generic.List`1[[Tester.ExampleClass, Tester]], System.Private.CoreLib",
  "$values": [
    {
      "$type": "Tester.ExampleClass, Tester",
      "Key": 123,
      "Name": "Test"
    }
  ]
}

.. and so we've successfully removed some of the assembly names as there is no mention of "System.Private.CoreLib" in the List's type and the $type string for the ExampleClass instance no longer mentions the "Tester" assembly name but the generic type of the List does mention the "Tester" assembly name and we were trying to prevent assembly names from appearing in the type data!

I've had a good Google around this and there doesn't seem to be a definitive answer anywhere and I had a need for one, so I've put together a solution that does what I need. There is an answer to a similar(ish) stack overflow question here but it ends with a disclaimer that the regex provided would need tweaking to support nested types and a) I definitely wanted to support nested generic type parameters (eg. a Dictionary that maps string keys to List-of-int values) and b) regexes and me are not the best of friends - hence my going about it my own way!

public sealed class TypeNameAssemblyExcludingSerializationBinder : ISerializationBinder
{
    public static TypeNameAssemblyExcludingSerializationBinder Instance { get; }
        = new TypeNameAssemblyExcludingSerializationBinder();
    private TypeNameAssemblyExcludingSerializationBinder() { }

    public void BindToName(Type serializedType, out string assemblyName, out string typeName)
    {
        // Note: Setting the assemblyName to null here will only remove it from the main type itself -
        // it won't remove it from any types specified as generic type parameters (that's what the
        // RemoveAssemblyNames method is needed for)
        assemblyName = null;
        typeName = RemoveAssemblyNames(serializedType.FullName);
    }

    public Type BindToType(string assemblyName, string typeName)
    {
        // Note: Some additional work may be required here if the assembly name has been removed
        // and you are not loading a type from the current assembly or one of the core libraries
        return Type.GetType(typeName);
    }

    private static string RemoveAssemblyNames(string typeName)
    {
        var index = 0;
        var content = new StringBuilder();
        RecusivelyRemoveAssemblyNames();
        return content.ToString();

        void RecusivelyRemoveAssemblyNames()
        {
            // If we started inside a type name - eg.
            //
            //   "System.Int32, System.Private.CoreLib"
            //
            // .. then we want to look for the comma that separates the type name from the assembly
            // information and ignore that content. If we started inside nested generic type content
            // - eg.
            //
            //  "[System.Int32, System.Private.CoreLib], [System.String, System.Private.CoreLib]"
            //
            // .. then we do NOT want to start ignoring content after any commas encountered. So
            // it's important to know here which case we're in.
            var insideTypeName = typeName[index] != '[';

            var ignoreContent = false;
            while (index < typeName.Length)
            {
                var c = typeName[index];
                index++;

                if (insideTypeName && (c == ','))
                {
                    ignoreContent = true;
                    continue;
                }

                if (!ignoreContent)
                    content.Append(c);

                if (c == '[')
                    RecusivelyRemoveAssemblyNames();
                else if (c == ']')
                {
                    if (ignoreContent)
                    {
                        // If we encountered a comma that indicated that we were about to start
                        // an assembly name then we'll have stopped adding content to the string
                        // builder but we don't want to lose this closing brace, so explicitly
                        // add it in if that's the case
                        content.Append(c);
                    }
                    break;
                }
            }
        }
    }
}

A note about resolving types from type names (without assemblies)

In .NET, the "Type.GetType" method will return null if it is given a type name that does not correspond to a type that exists in either the current assembly or in one of the core .NET libraries. In Bridge.NET, it doesn't appear that they maintained that requirement and I believe that all types are available, even if an assembly name is not specified - but whether it is or isn't, a similar approach could be used in both cases where you use reflection to look at all loaded assemblies and all of their available types and try to map assembly-name-less type names onto one of those. Getting into this would be completely out of the scope of this post and I'm hoping that you already have an idea in mind if you had got to the point where you wanted to remove all assembly names from your type metadata!

Posted at 17:25

Comments

Type aliases in Bridge.NET (C#)

Back in 2016, I wrote Writing React apps using Bridge.NET - The Dan Way (Part Three) and I talked about trying to tighten up the representation of values in the type system. One of my pet peeves that I talked about was how "no value" is represented in reference types and, in particular, with strings.

As a reminder, I was having a rant about how I hate the uncertainty of wondering "should I expect to get null passed in here / returned from here" and I decided to draw a hard line and say that no, in my code I would never expect a reference type to have a null value - instead I would always use the Optional<T> struct that I included in my NuGet package ProductiveRage.Immutable. This allows me to make it clear when a method may return a null value (because its return type would be something like Optional<PersonDetails>) and it would allow me to make it clear when a method will and won't accept null arguments (it will if the parameter type is Optional<T> and it won't if it's not).

Strings, however, have another "no value" state - when they are blank. If I want to have a method argument whose type indicates "this argument must be a string that is not null AND that is not blank" then we can't communicate that. To address that, my blog post introduced another type; the NonBlankTrimmedString -

public class NonBlankTrimmedString
{
    public NonBlankTrimmedString(string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException("Null, blank or whitespace-only value specified");
        Value = value.Trim();
    }

    /// <summary>
    /// This will never be null, blank or have any leading or trailing whitespace
    /// </summary>
    public string Value { get; }

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a string
    /// </summary>
    public static implicit operator string(NonBlankTrimmedString value)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        return value.Value;
    }
}

This would allow me to have a method that clearly indicates that it needs a string with a real value - eg.

void DoSomething(NonBlankTrimmedString value);

.. and it could be combined with Optional<T> to define a method whose type signature indicates that it will take a string with a real value OR it will accept a "no value" - eg.

void DoSomething(Optional<NonBlankTrimmedString> value);

This method will not accept a blank string because that's just another state that is not necessary; either you give me a real (non-blank) value or you don't. There is no half-way house of "non-null but still with no value".

As another example, I might want to write a Bridge.React component whose Props type can optionally take an additional class name to render as part of the component - in which case, I might write the class a bit like this:

public sealed class Props
{
    public Props(
        /* .. other property values, */
        Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
    {
        // .. other properties set here
        ClassName = className;
    }

    // .. other public properties exposed here

    public Optional<NonBlankTrimmedString> ClassName { get; }
}

This is all fine and dandy and, pretty much, it just works. If I want to expand this richer type system so that it's used in API requests / responses as well then I can have Optional<T> and NonBlankTrimmedString types defined in the .NET code that runs on the server as well as in my Bridge project. And if I want to avoid code duplication then I can define the types in a Shared Project that is referenced by both the Bridge project and the server API project.

One downside to this approach, though, is that JSON payloads from API calls are going to be larger if I wrap all of my strings in NonBlankTrimmedString instances. And there will be more work for Bridge's version of Newtonsoft Json.NET to do because it has to parse more data and it has to deserialise more instances of types; for every string, instead of just deserialising a value into a string, it needs to deserialise that string value and then create an instance of a NonBlankTrimmedString to wrap it. If you have any API calls that return 100s or 1000s of strings then this can become a non-negligible cost.

The full .NET version of Newtonsoft Json.NET has some flexibility with how types are serialised to/from JSON. For example, if I wanted to tell the serialiser that NonBlankTrimmedString instances should appear in the JSON as plain strings then I could do so using a JsonConverter (there is sample code in the Newtonsoft website that demonstrates how to do it for the Version type and the principle would be exactly the same for NonBlankTrimmedString - see Custom JsonConverter<T>).

The Bridge version of the library has no support for custom JsonConverters, though, so we may appear to be a bit stuck.. if it weren't for the fact that Bridge has some low-level tricks that we can use to our advantage.

In order to allow C# code to be written that interacts with JavaScript libraries, Bridge has a few escape hatches for the type system that we can use in a careful manner. For example, I could rewrite the Bridge version of NonBlankTrimmedString to look like this:

public class NonBlankTrimmedString
{
    protected NonBlankTrimmedString() { }

    /// <summary>
    /// This will never be null, blank or have any leading or trailing whitespace
    /// </summary>
    public extern string Value { [Template("{this}")] get; }

    /// <summary>
    /// Create a NonBlankTrimmedString instance by explicitly casting a string
    /// </summary>
    public static explicit operator NonBlankTrimmedString(string value)
    {
        if (value == null)
            return null;
        value = value.Trim();
        if (value == "")
            throw new ArgumentException("Can not cast from a blank or whitespace-only string");
        return Script.Write<NonBlankTrimmedString>("value");
    }

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a string
    /// </summary>
    [Template("{value}")]
    public extern static implicit operator string(NonBlankTrimmedString value);
}

This changes things up a bit. Now there is no public constructor and the only way to get a NonBlankTrimmedString instance from a plain string is to explicitly cast to it - eg.

var x = (NonBlankTrimmedString)"hi!";

If the source string is blank or whitespace-only then attempting to cast it to a NonBlankTrimmedString will result in an exception being thrown.

What's interesting about this class is that it exists only to provide type information to the C# compiler - there will never be an instance of NonBlankTrimmedString alive runtime in JavaScript. The reason for this is that the explicit cast performs some validation but then, at runtime, returns the string instance directly back; it doesn't wrap it in an instance of a NonBlankTrimmedString class. Similarly, when the "Value" property is requested in C# code, this is translated into JS as a direct reference to "this" (which we know is a plain string). This is sounding complicated as I write this, so let me try to make it clear with an example!

The following C# code:

// Start with a plain string
var source = "Hi!";

// Create a NonBlankTrimmed by explicitly casting the string
var x = (NonBlankTrimmedString)source;

// Write the value of the NonBlankTrimmedString to the console
Console.WriteLine(x.Value);

.. is translated into this JS:

// Start with a plain string
var source = "Hi!";

// Create a NonBlankTrimmed by explicitly casting the string
var x = Demo.NonBlankTrimmedString.op_Explicit(source);

// Write the value of the NonBlankTrimmedString to the console
System.Console.WriteLine(x);

The reference "x" in the JS runtime is actually just a string (and so the C# "x.Value" is translated into simply "x") and the explicit operator (the method call "Demo.NonBlankTrimmedString.op_Explicit") performs some validation but then (if the validation passes) returns the string right back but claims (for the benefit of the C# compiler and type system) that it is now a NonBlankTrimmedString.

This has a couple of benefits - now, plain string values that appear in JSON can be deserialised into NonBlankTrimmedString instances by Bridge (while the Bridge version of Json.NET doesn't support type converters, it does support deserialising types using implicit or explicit operators - so, here, it would see a string in the JSON and see that the target type was a NonBlankTrimmedString and it would use NonBlankTrimmedString's explicit operator to instantiate the target type), so the JSON returned from the server can be cleaner. And it means that the JS runtime doesn't have to actually create instances of NonBlankTrimmedString to wrap those strings up in, which makes the life of the garbage collector easier (again, may be important if you have API responses that need to return 1000s of NonBlankTrimmedString).

This is an interesting concept that I'm referring to as a "type alias" - a type that exists only for the compiler and that doesn't affect the runtime. The phrase "type alias" exists in TypeScript and in F# (and in other languages, I'm sure) but I think that it means something slightly different there.. which may mean that I've chosen a confusing name for this C# / Bridge.NET concept! In TypeScript and F#, I don't believe that they allow the level of compiler validation that I'm talking about - certainly in TypeScript, type aliases are more of a convenience that allow you say something like:

type Vector = number[];
type Vectors = Vector[];

.. so that you can then write a method signature that looks like this:

function process(data: Vectors) {
    // ..
}

.. instead of:

function process(data: number[][]) {
    // ..
}

.. but the two are identical. TypeScript "type aliases" make things more flexible, not more constrained. To make that clearer, if you wrote:

type CustomerID = number;

function process(id: CustomerID) {
    // ..
}

.. then you could still call:

process(1); // Passing a plain number into a method whose signature specifies type CustomerID

In other words, the TypeScript alias means "anywhere that you see CustomerID, you can pass in a 'number'". This is the opposite of what I want, I want to be able to have methods that specify that they want a NonBlankTrimmedString and not just any old string.

I go into this in a little more detail in the section "Type aliases in other languages" at the end of this blog post. My point here was that maybe "type alias" is not the best phrase to use and maybe I'll revisit this in the future.

For now, though, let's get back to the NonBlankTrimmedString definition that I've proposed because it has some downsides, as well. As the type only exists at compile time and not at runtime, if I try to query the type of a NonBlankTrimmedString instance at runtime then it will report that it is a "System.String" - this is to be expected, since part of the benefit of this approach is that no additional instances are required other than the plain string itself - but if you were wanted to do some crazy reflection for some reason then it might catch you off guard.

Another downside is that if I wanted to create specialised versions of NonBlankTrimmedString then I have to duplicate some code. For example, I might want to strongly type my entity IDs and define them as classes derived from NonBlankTrimmedString. With the version of NonBlankTrimmedString from my 2016 blog post, this would be as simple as this:

// If NonBlankTrimmedString is a regular class then creating derived types is easy as this
public class OrderID : NonBlankTrimmedString
{
    public OrderID(string value) : base(value) { }
}

.. but with this "type alias" approach, it becomes more verbose -

// The explicit operator needs to be reimplemented for each derived type with the type alias
// alias approach shown earlier :(
public class ClassName : NonBlankTrimmedString
{
    protected ClassName() { }

    public static explicit operator ClassName(string value)
    {
        if (value == null)
            return null;
        value = value.Trim();
        if (value == "")
            throw new ArgumentException("Can not cast from a blank or whitespace-only string");
        return Script.Write<ClassName>("value");
    }
}

However, we could make this a little simpler by changing the NonBlankTrimmedString type definition to this:

public class NonBlankTrimmedString
{
    protected NonBlankTrimmedString() { }

    /// <summary>
    /// This will never be null, blank or have any leading or trailing whitespace
    /// </summary>
    public extern string Value { [Template("{this}")] get; }

    /// <summary>
    /// Create a NonBlankTrimmedString instance by explicitly casting a string
    /// </summary>
    public static explicit operator NonBlankTrimmedString(string value)
        => Wrap<NonBlankTrimmedString>(value);

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a string
    /// </summary>
    [Template("{value}")]
    public extern static implicit operator string(NonBlankTrimmedString value);

    protected static T Wrap<T>(string value) where T : NonBlankTrimmedString
    {
        if (value == null)
            return null;
        value = value.Trim();
        if (value == "")
            throw new ArgumentException("Can not cast from a blank or whitespace-only string");
        return Script.Write<T>("value");
    }
}

.. and then derived types would look like this:

public class OrderID : NonBlankTrimmedString
{
    protected OrderID() { }
    public static explicit operator OrderID(string value) => Wrap<OrderID>(value);
}

(Sort-of-)immutability for "free" through type aliases

Another use case where this sort of approach seemed interesting was when I was writing some client-side code that received data in the form of arrays and then did some clever calculations and drew some pretty graphs. The API response data was 10s of 1000s of arrays, where each array was 100 floating point numbers. The calculation logic took those arrays and passed them through a bunch of methods to come up with the results but I got myself in a bit of a muddle when there were one or two places that had to manipulate a subset of the data and I realised that I was confusing myself as to whether the data should be altered in place or whether local copies of those parts of the data should be taken and then changed. To make the code easier to follow, I wanted those methods to take local copies to make the changes, rather than mutating them in-place and risking messing up calculations performed on the data later in the pipeline.

What I really wanted was for those methods to have type signatures that would either take an immutable data type or a readonly data type. Immutable is the ideal because it means that not only can the receiving methods not change the data but nothing can change the data. Having readonly types on the method signatures means that the methods can't change the data but it's still technically possible for the caller to change the data. To try to illustrate this, I'll use the ReadOnlyCollection<T> type from .NET in an example:

public static void Main()
{
    var items = new List<int> { 0, 1, 2, 3 };
    var readOnlyItems = items.AsReadOnly();
    DoSomething(
        readOnlyItems,
        halfwayPointCallback: () => items.RemoveAt(0)
    );
}

static void DoSomething(ReadOnlyCollection<int> readOnlyItems, Action halfwayPointCallback)
{
    Console.WriteLine("Number of readonlyItems: " + readOnlyItems.Count);
    halfwayPointCallback();
    Console.WriteLine("Number of readonlyItems: " + readOnlyItems.Count);
}

Here, the "Main" method declares a mutable list and then it create a readonly wrapper around it. The readonly wrapper is passed into the "DoSomething" method and this means "DoSomething" can not directly alter that list. However, it's still possible for the "Main" method to change the underlying list while "DoSomething" is running.

In practice, this is not something that I find commonly happens. As such, while I would prefer immutable structures at all times (because then "Main" couldn't change the contents of the list while "DoSomething" is working on it), being able to wrap the data in a readonly structure is still a significant improvement.

So, some of the more obvious options available to me were:

  1. Stick with using arrays and be careful not to write code that performs any alteration "in place" (I don't like this situation - C#'s type system has great potential and I want it to help me and save me from myself where possible!)
  2. Pass the arrays into the methods as IEnumerable<float> (this isn't a terrible idea in general - it quite clearly communicates that the provided data should be considered read only - but the calculations that I was doing wanted to get the length of the array and to read particular indexed values from the array in unpredictable orders and this isn't very efficient with enumerable types)
  3. Create an "immutable list" class that takes an array into the constructor, copies the data and then allows access to the copy only through tightly-controlled members; ie. Length and an indexed property (This is the most type-safe way but it felt expensive doing this for the 10s of 1000s of arrays that I had)
  4. Convert each array into a List<float> and then call ".AsReadOnly()" on them (this is very little code but it also felt expensive with the amount of data that I had)
  5. Create a "ReadOnlyArray<T>" type that would be very similar in nature to the ReadOnlyCollection<T> in that it would take an array into its constructor and then provide a read only interface for it, without copying the array (This is a reasonable option and I might have gone this way were it not for liking the idea of option six)
  6. Create a "ReadOnlyArray<T>" type alias that I could use to instruct the type system that the data should not be altered but without having to introduce any new types or instances at runtime

I went with the last one because I was all excited about experimenting with "Bridge.NET type aliases" and I wanted to see how well they could work! (In reality, the fifth option was also a good one and some of the others would also be perfectly fine for smaller data sets.. to be honest, there is a chance that they wouldn't have made too much difference even with the data that I was looking at but, again, sometimes you need to make opportunity to experiment! :)

public sealed class ReadOnlyArray<T> : IEnumerable<T>
{
    [Template("{data}")]
    public extern ReadOnlyArray(T[] data);

    [External] // Required due to https://github.com/bridgedotnet/Bridge/issues/4015
    public extern T this[int index] { [Template("{this}[{index}]")] get; }

    public extern int Length { [Template("length")] get; }

    [External]
    public extern IEnumerator<T> GetEnumerator();

    [External]
    extern IEnumerator IEnumerable.GetEnumerator();

    [Template("{value}")]
    public extern static implicit operator ReadOnlyArray<T>(T[] value);
}

The structure of this class is similar in some ways to that of the NonBlankTrimmedString. Unlike that class, there is no validation that is required - I only want to provide access to an array in a limited manner and so it's fine to expose a public constructor (as opposed to the NonBlankTrimmedString, where it's important to check that the value is neither null nor blank nor whitespace-only and the [Template] attribute on the constructor doesn't easily allow for any validation).

Even though the constructor may be used on this class, there is still an operator to change an array into a ReadOnlyArray so that the deserialisation process is able to read an array of items into a ReadOnlyArray instance. I've chosen to use an implicit operator (rather than en explicit operator) here because there is no validation to perform - the NonBlankTrimmedString has an explicit operator because thatdoes perform some validation and so it's a casting action that could fail and so I want it to be explicit in code.

As with the NonBlankTrimmedString, this type will exist only at compile time and the compiled JavaScript will always be operating directly against the original array. As far as the JS code is aware, there is no wrapper class involved at all. The following C# -

var values = new[] { 1, 2, 3 };
Console.WriteLine(values.Length);

var readOnlyValuesCtor = new ReadOnlyArray<int>(values);
Console.WriteLine(readOnlyValuesCtor.Length);

ReadOnlyArray<int> readOnlyValuesCast = values;
Console.WriteLine(readOnlyValuesCast.Length);

.. is translated into this JS:

var values = System.Array.init([1, 2, 3], System.Int32);
System.Console.WriteLine(values.length);

var readOnlyValuesCtor = values;
System.Console.WriteLine(readOnlyValuesCtor.length);

var readOnlyValuesCast = values;
System.Console.WriteLine(readOnlyValuesCast.length);

Whether the ReadOnlyArray<int> is created by calling its constructor or by an implicit cast in the C# code, the JS is unaware of any change required of the reference and continues to operate on the original array. This is the "free" part of this approach - there is no runtime cost in terms of type conversions or additional references.

The other members of the class need a little more explanation, though. The indexer should be implemented just like the "Length" property, by having an extern property that has a getter with a [Template] attribute on it. However, there is a bug in the Bridge compiler that necessitate an additional [External] attribute be added to the property. Not the end of the world and I'm sure that the Bridge Team will fix it in a future version of the compiler.

The "GetEnumerator" methods require a tiny bit more explanation. In order for the class to implement IEnumerable<T>, these methods must be present. But we don't actually have to implement them ourselves. Whenever Bridge encounters a "foreach" in the source C# code, it translates it into JS that calls "GetEnumerator" and then steps through each value. For example, this C# code:

foreach (var value in readOnlyValuesCtor)
    Console.WriteLine(value);

.. becomes this JS:

$t = Bridge.getEnumerator(readOnlyValuesCtor);
try {
    while ($t.moveNext()) {
        var value = $t.Current;
        System.Console.WriteLine(value);
    }
} finally {
    if (Bridge.is($t, System.IDisposable)) {
        $t.System$IDisposable$Dispose();
    }
}

Because Bridge needs to support enumerating over arrays, the function "Bridge.getEnumerator" knows what to do if it is given an array reference. And since a ReadOnlyArray is an array reference at runtime, we don't have to do anything special - we don't have to provide a GetEnumerator implementation.

And there we go! As I explained above, I originally encountered this problem when passing an array into a complicated calculation process but this type could also be used for deserialising JSON into a richer type model, just like the NonBlankTrimmedString earlier - again, without any overhead in doing so (no instances of wrapper types will be present runtime and there will be no additional references for the garbage collector to track).

Only possible in Bridge.NET?

I was wracking my brains about whether it would be possible to do something similar with C# running in a .NET environment and I couldn't think of anything. People sometimes think "structs!" when trying to concoct ways to avoid adding references that the garbage collector needs to track but structs are only immune to this if they don't contain any object references within their fields and properties (and there are other edge cases besides this but they're not important right now).

At the end of the day, this "type alias" concept might be a bit of a niche technique and it might even be a case of me playing around, more than it being something that you might use in production.. but I thought that it was interesting nonetheless. And it has made me wish, again, that C# had support for something like this - I've written code before that defines all variety of strongly typed IDs (strings) and Keys (integers) to avoid passing the wrong type of value into the wrong place but it's always felt cumbersome (it's felt worth the effort but that didn't stop wishing me that it was less effort).

Type aliases in other languages

I've linked above to an article Using strongly-typed entity IDs to avoid primitive obsession, which is excellent and eloquently expresses some of my thoughts, but I thought that I'd add a summary in here as well (which also gives me an opportunity to go into more detail about the options in TypeScript and F#).

I'll start with an anecdote to set the scene. In a company that I used to work at, we had systems that would retrieve and render different data for different language options. Sometimes data would vary only by language ("English", "French", etc..) but sometimes it would be more specific and vary by language culture (eg. "English - United Kingdom", "English - United States", etc..). An older version of the system would pass around int values for the language or language culture keys. So there might be a method such as:

private string GetTranslatedName(int languageKey)

A problem that occurred over and over again is that language keys and language culture keys would get mixed up in the code base - in other words, it was quite common for someone to accidentally pass a language key into a method where a language culture key was expected (this situation was not helped by the fact that much of the developer testing was done in English and the language key and language culture key values in many of the databases were both 1 for English / English UK). Something that I was very keen to get into a new version of the system was to introduce "strongly typed keys" so that this sort of accident could no longer occur. The method's signature would be changed to something like this:

private string GetTranslatedName(LanguageKey languageKey)

.. and we would not describe language or language culture keys as ints in the code base. They would always be either an instance of LanguageKey or LanguageCultureKey - this way, if you attempted to pass a key of the wrong type into a method then you would get a compile error.

The downside is that each key type had to be defined as its own struct, with the following (quite verbose) structure:

public struct LanguageKey : IEquatable<LanguageKey>
{
    public LanguageKey(int value) => Value = value;

    public int Value { get; }

    public bool Equals(LanguageKey other) => Value.Equals(other.Value);
    public override bool Equals(object obj) => (obj is LanguageKey key) && (key.Value == Value);
    public override int GetHashCode() => Value;

    public static bool operator ==(LanguageKey x, LanguageKey y) => x.Value == y.Value;
    public static bool operator !=(LanguageKey x, LanguageKey y) => !(x == y);

    public static explicit operator LanguageKey(int value) => new LanguageKey(value);
}

Really, though, that is the only downside. As the strongly typed keys are structs without any reference properties or fields, there is no additional work for the garbage collector and there is no memory overhead vs tracking a simple int. But it does still feel a little arduous to have to have these definitions in the code base, particularly when the equivalent F# code looks like this:

[<Struct>] type LanguageKey = LanguageKey of int

It's worth noting that this is not actually referred to as a "type alias" in F#; this is a "single case union type". There is a concept called a "type alias" in F# that looks like this:

type LanguageKey = int

.. but that code simply says "allow me to use the word 'LanguageKey' anywhere in place of int" - eg. if I have the LanguageKey type alias specified as a method argument type in F# method, like this:

let getTranslatedName (language: LanguageKey) =
    // (Real work to retrieve translated name would go here but we'll
    //  just return the string "Whatever" for the sake of this example)
    "Whatever"

.. then the compiler would allow me to pass an int into that method -

// A LanguageKey type alias lets me pass any old int into the method - rubbish!
let name = getTranslatedName 123

.. and that's exactly what I wanted to avoid!

On the other hand, if the type LanguageKey was a "single case union type" then the code above would not compile:

// error FS0001: This expression was expected to have type 'LanguageKey' but here has type 'int'
let name = getTranslatedName 123

// This DOES compile because the types match
let key = LanguageKey 123
let name = getTranslatedName 123

.. and that's exactly what I did want!

(TypeScript's type aliases are like F#'s type aliases - they are more of a convenience and do not add the sort of type checking that I want)

Things get a bit more awkward if we want to deal with reference types, such as strings, because we could create a C# class similar to LanguageKey (or we could create an F# single case union type) but that would introduce a new instance of a type that must be tracked by the garbage collector - every strongly typed ID involves two references; the underlying string value and the strongly typed wrapper. Much of the time, that's no problem - I've had the odd issue with the .NET GC in the past but, on the whole, it's an amazing and reliable tool.. but because I have had these problems before, it makes me more aware of the trade-off when I introduce wrappers like this.

I'm convinced that using strongly typed IDs is the right thing to do in 99% of cases because it improves code quality and can eradicate a class of real-world mistake. But the concept became even more interesting to me as it appeared possible to introduce a form of type alias into Bridge.NET code that enables those compile time checks but with zero runtime cost. Granted, the type erasure that occurs means that runtime type checking is not possible (the Bridge code can not differentiate between a string or a NonBlankTrimmedString or a type that is derived from NonBlankTrimmedString) but the main driver for me was to improve compile time checking and so that wasn't a problem for me. Maybe it would be a problem in other scenarios, in which case these Bridge.NET "type aliases" might not be appropriate.

Posted at 21:59

Comments

Performance tuning a Bridge.NET / React app

On the whole, React is fast. And, on the whole, writing a web application's code in C# using Bridge.NET has little overhead compared to writing it directly in JavaScript since Bridge generates sensible JavaScript.

However, I recently wanted to convince myself that performance would not be an issue with the sort of projects that we'll be writing at work. We have some applications that are key to the business and yet have unfortunately been left to wither into a barely-maintainable state. The plan is to, over time, rewrite sections of the application using Bridge and React so that the application continues to work at all times but the old code is pruned away. This means that we need to be sure that any crazy forms that existed in the old codebase will work fine in the new architecture. In particular, there is a configuration page that allows a user to select options from a list of almost 1,000 checkboxes. Is this good UI? Most probably not. Do we need to be able to support such configurations in the future? Unfortunately, most probably yes. With a classic server-based MVC application, this would involve 1,000 checkboxes being rendered on the page and then a ginormous form post to send the changes back when the user clicks Save. In a React app, this sort of form will require virtual re-renders each time that a checkbox is clicked on.

I thought I'd actually go with something slightly more demanding - 5,000 rows on a form where each row has two text boxes and a checkbox. If this can be handled easily then the worst case scenario that we have in mind for our rewrites (1,000 checkboxes) will be a walk in the park.

So I whipped up a sample app and started using the Chrome profiler.. and the news was not good.

The total time recorded by the profiler was 838ms to deal with the changing of a single checkbox. It's said that 100ms is "the limit for having the user feel that the system is reacting instantaneously" and 838ms is just not in the same ballpark. What's even worse is that this delay is experienced not only when a checkbox state is changed but also when any change is applied to one of the text boxes. Waiting almost a second for a checkbox to change is bad but waiting that long for each key press to be registered while typing is unbearable.

Examining the test app

The test app is fairly simple (and will contain no surprises if you've read my Writing React apps using Bridge.NET - The Dan Way three part mini-series). However, the performance improvements that I'm going to cover will be in versions of libraries that I haven't yet released - namely, Bridge.React, ProductiveRage.Immutable and ProductiveRage.Immutable.Extensions. The ProductiveRage.Immutable.Extensions library includes types that I commonly use when writing Bridge / React apps (such as RequestId and NonBlankTrimmedString). So you won't yet be able to try out the changes that I'm going to discuss but (hopefully!) the process of identifying what changes to make will be useful.

(I'm planning to release the updates to these libraries around the time that Bridge 15.0 comes out, which should hopefully be this month - this will include the change to using Roslyn for parsing the C#, rather than NRefactory, and so C# 6 syntax will finally be supported, which is wonderful news).

One of the types that will be available in ProductiveRage.Immutable.Extensions is CommonProps<T>. It's extremely common for component classes to require the same sort of information - what the initial state is, how to record requests to change that state, what class name to apply to the component, whether it should be in a disabled state or not and what key the component has (for cases where it appears as part of a set of dynamic child components).

public sealed class CommonProps<T> : IAmImmutable
{
    public CommonProps(
        T state,
        Action<T> onChange,
        Optional<ClassName> className,
        bool disabled,
        Optional<Any<string, int>> key)
    {
        this.CtorSet(_ => _.State, state);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Disabled, disabled);
        this.CtorSet(_ => _.Key, key);
    }

    public T State { get; private set; }
    public Action<T> OnChange { get; private set; }
    public Optional<ClassName> ClassName { get; private set; }
    public bool Disabled { get; private set; }
    public Optional<Any<string, int>> Key { get; private set; }
}

If you have a custom text box component then you want to be able to set the initial text value and to be informed when the user is performing an action that changes the text value. If you have a row in a table that shows a message (such as in the application built up in the three part series) then each row needs to have state describing what to show in the "Content" text box and what to show in the "Author" text box. When the user tries to change of those values, the row needs to have a way to say that the current message state is changing. As a final example, if there is a Message table component then the initial state will be a set of messages to render and the "OnChange" delegate will be used whenever a user wants to change a value in an existing row or when they want to remove a row or when they want to add a row. So it's a very common pattern and having a generic class to describe it means that there's less code to write for each component, since they can use this common class rather than each component having their own props class.

There are some static factory methods to make initialising CommonProps<T> instances easier:

public static class CommonProps
{
    public static CommonProps<T> For<T>(
        T state,
        Action<T> onChange,
        Optional<ClassName> className,
        bool disabled)
    {
        return new CommonProps<T>(
            state,
            onChange,
            className,
            disabled,
            Optional<Any<string, int>>.Missing
        );
    }

    public static CommonProps<T> For<T>(
        T state,
        Action<T> onChange,
        Optional<ClassName> className,
        bool disabled)
        Any<string, int> key)
    {
        return new CommonProps<T>(state, onChange, className, disabled, key);
    }
}

With that in mind, the code below should be easy to understand. For simplicity, state changes are handled directly by the container component (there is no Dispatcher) and all that the app does is render 5,000 rows and allow the user to change either text box in each row or the checkbox that each row has. It might seem like a lot of code but that's partly due to the way that the lines are wrapped to fit in the blog post and it's partly because I've included all of the non-shared-library code from the app, which is important so that we can talk about what is and isn't worth altering.

public static class App
{
    [Ready]
    public static void Main()
    {
        React.Render(
            new AppContainer(),
            Document.GetElementById("main")
        );
    }
}

public sealed class AppContainer : Component<object, AppContainer.State>
{
    public AppContainer() : base(null) { }

    protected override State GetInitialState()
    {
        return new State(
            Enumerable.Range(1, 5000)
                .Select(i => Saved.For(
                    i.ToString(),
                    new MessageEditState("Title" + i, "Content" + i, isAwesome: false)))
                .ToSet()
        );
    }

    public override ReactElement Render()
    {
        return DOM.Div(
            new Attributes { ClassName = "wrapper" },
            new MessageTable(
                state.Messages,
                updatedMessages => SetState(new State(updatedMessages)),
                className: new ClassName("messages"),
                disabled: false
            )
        );
    }

    public sealed class State : IAmImmutable
    {
        public State(NonNullList<Saved<MessageEditState>> messages)
        {
            this.CtorSet(_ => _.Messages, messages);
        }

        public NonNullList<Saved<MessageEditState>> Messages { get; private set; }
    }
}

public sealed class Saved<T> : IAmImmutable
{
    public Saved(string id, T value)
    {
        this.CtorSet(_ => _.Id, id);
        this.CtorSet(_ => _.Value, value);
    }

    public string Id { get; private set; }
    public T Value { get; private set; }
}

public static class Saved
{
    public static Saved<T> For<T>(string id, T value)
    {
        return new Saved<T>(id, value);
    }
}

public sealed class MessageEditState : IAmImmutable
{
    public MessageEditState(string title, string content, bool isAwesome)
    {
        this.CtorSet(_ => _.Title, title);
        this.CtorSet(_ => _.Content, content);
        this.CtorSet(_ => _.IsAwesome, isAwesome);
    }

    public string Title { get; private set; }
    public string Content { get; private set; }
    public bool IsAwesome { get; private set; }
}

public sealed class MessageTable : PureComponent<CommonProps<NonNullList<Saved<MessageEditState>>>>
{
    public MessageTable(
        NonNullList<Saved<MessageEditState>> state,
        Action<NonNullList<Saved<MessageEditState>>> onChange,
        Optional<ClassName> className,
        bool disabled)
            : base(CommonProps.For(state, onChange, className, disabled)) { }

    public override ReactElement Render()
    {
        return DOM.Div(
            new Attributes { ClassName = props.ClassName.ToNullableString() },
            props.State.Select((savedMessage, index) => new MessageRow(
                savedMessage.Value,
                updatedMessage => props.OnChange(
                    props.State.SetValue(index, props.State[index].With(_ => _.Value, updatedMessage))
                ),
                className: null,
                disabled: false,
                key: savedMessage.Id
            ))
        );
    }
}

public sealed class MessageRow : PureComponent<CommonProps<MessageEditState>>
{
    public MessageRow(
        MessageEditState state,
        Action<MessageEditState> onChange,
        Optional<ClassName> className,
        bool disabled,
        Any<string, int> key)
            : base(CommonProps.For(state, onChange, className, disabled, key)) { }

    public override ReactElement Render()
    {
        return DOM.Div(new Attributes { ClassName = props.ClassName.ToNullableString() },
            props.TextBoxFor(_ => _.Title, "title"),
            props.TextBoxFor(_ => _.Content, "content"),
            props.CheckboxFor(_ => _.IsAwesome, "is-awesome")
        );
    }
}

public static class CommonPropsRenderer
{
    public static ReactElement TextBoxFor<T>(
        this CommonProps<T> props,
        [PropertyIdentifier]Func<T, string> propertyIdentifier,
        string className)
            where T : IAmImmutable
    {
        if (props == null)
            throw new ArgumentNullException("props");
        if (propertyIdentifier == null)
            throw new ArgumentNullException("propertyIdentifier");

        return DOM.Input(new InputAttributes
        {
            ClassName = className,
            Value = propertyIdentifier(props.State),
            OnChange = e => props.OnChange(props.State.With(propertyIdentifier, e.CurrentTarget.Value))
        });
    }

    public static ReactElement CheckboxFor<T>(
        this CommonProps<T> props,
        [PropertyIdentifier]Func<T, bool> propertyIdentifier,
        string className)
            where T : IAmImmutable
    {
        if (props == null)
            throw new ArgumentNullException("props");
        if (propertyIdentifier == null)
            throw new ArgumentNullException("propertyIdentifier");

        return DOM.Input(new InputAttributes
        {
            Type = InputType.Checkbox,
            ClassName = className,
            Checked = propertyIdentifier(props.State),
            OnChange = e => props.OnChange(props.State.With(propertyIdentifier, e.CurrentTarget.Checked))
        });
    }
}

Except for the top-level AppContainer, every component is derived from PureComponent<T> which means that they automatically get implementations for React's "shouldComponentUpdate" component life cycle method. This means that if a component needs to be re-rendered by the virtual DOM and if the new props settings are the same as its current props settings then the component will tell React "I'm not going to change, you do not need to re-render me (nor any of my child components)". I had originally hoped that this would mean that everything would be blazing fast without any additional work. However, as I've already said, this was not to be the case.

Before I get stuck in, it's worth bearing in mind that this really is a worst case scenario. If there was a page that required 5,000 entry rows spread over ten different tables then changing any single row would only require the containing table to re-render, the other nine would not need to (the PureComponent<T>'s "shouldComponentUpdate" logic would take take of that). The difficulty here is that all 5,000 rows are in a single table and so changing any value in any row requires that the table potentially re-render all of its rows. I can't imagine very many UIs where presenting a user with so many rows simultaneously would be a particularly pleasant experience. Perhaps a spreadsheet of some sort? If you needed to present an interface with tens of thousands of inputs, there are ways to make it faster such as "chunking up" groups of rows (so that a change to any single row only requires the other rows in the group potentially to re-render and not any other group). A more complicated (but highly efficient) approach would be to work out what data is currently visible in the browser window and to only update that.

Rather than considering these alternatives at this point, though, I want to see what we can do with the sample app as it's presented.

Profiling

Initial timings (not good)

The first thing to do was to start measuring and digging. I loaded the page in Chrome, opened the dev tools, went to the Profiles tab, clicked "Start CPU profiling", clicked a checkbox and then "Stop CPU profiling". The result is shown here. There is a natural split between two processes - the "Render" method of the MessageTable and the "receiveComponent" / "updateComponent" within React. I know that it's the MessageTable's Render method because it calls "select" (the LINQ function) and that will be where the MessageTable creates each MessageRow. I'm going to concentrate there first since that's where most of the time is taken and it's also what I have the most direct control over.

Just one thing to check first, though - I'm using the development build of the React library at this point, which has some overhead compared to the production version (since it performs more checks and does more work in order to provide more helpful warnings, where required). Changing to the production build trims some time off; the MessageTable "Render" method still takes 609ms but "receiveComponent" takes about half as much time, now 128ms. Clearly, the production build is not going to magically solve all of my problems.

The Chrome dev tools allow you to zoom in on sections of the profiler results, so I tried to make sense of what I could see under the "Render" side. The problem was that it seemed like there were lots of nested calls where none were individually very expensive, it seemed like a cumulative problem with just how many components there were. There were a lot of calls to "constructor", which suggested to me that there may be some overhead in creating Bridge classes. To try to test this theory, I added a new option to the React bindings to enable components to be created by providing a static function rather than creating a component class that is derived from Component<TProps, TState> or PureComponent<TProps>. This allows MessageRow to be rewritten as:

public static class MessageRow
{
    [Name("MessageRow")]
    public static ReactElement Render(CommonProps<MessageEditState> props)
    {
        return DOM.Div(new Attributes { ClassName = props.ClassName.ToNullableString() },
            props.TextBoxFor(_ => _.Title, "title"),
            props.TextBoxFor(_ => _.Content, "content"),
            props.CheckboxFor(_ => _.IsAwesome, "is-awesome")
        );
    }
}

which requires MessageTable to be changed to:

public sealed class MessageTable : PureComponent<CommonProps<NonNullList<Saved<MessageEditState>>>>
{
    public MessageTable(
        NonNullList<Saved<MessageEditState>> state,
        Action<NonNullList<Saved<MessageEditState>>> onChange,
        Optional<ClassName> className,
        bool disabled)
            : base(CommonProps.For(state, onChange, className, disabled)) { }

    public override ReactElement Render()
    {
        return DOM.Div(
            new Attributes { ClassName = props.ClassName.ToNullableString() },
            props.State.Select((savedMessage, index) => StaticComponent.Pure(
                MessageRow.Render,
                CommonProps.For(
                    savedMessage.Value,
                    updatedMessage => props.OnChange(
                        props.State.SetValue(index, props.State[index].With(_ => _.Value, updatedMessage))
                    ),
                    className: null,
                    disabled: false,
                    key: savedMessage.Id
                )
            ))
        );
    }
}

This way, there are 5,000 MessageRow constructor calls saved each time that the MessageTable needs to re-render. (Under the hood, there is still an object created for each row but it's a very lightweight JavaScript object).

This reduced the "Render" time to 496ms (it didn't affect "receiveComponent", but I didn't expect it to). This was a good start and made me want to look further into the cost of class instantiation in Bridge.

Bridge generic classes are more expensive

I whipped up a quick test to try creating lots of instances of a class, like this:

public static class App
{
    [Ready]
    public static void Main()
    {
        var x = new MyClass[10000];
        var timer = Stopwatch.StartNew();
        for (var i = 0; i < x.Length; i++)
            x[i] = new MyClass("test");
        timer.Stop();
        Console.WriteLine(timer.ElapsedMilliseconds + "ms");
    }
}

public class MyClass
{
    public MyClass(string value)
    {
        Value = value;
    }
    public string Value { get; private set; }
}

That only reported 3ms, which didn't seem like it could be the source of the problem.

Next I tried going one step more complicated. The MessageRow class that I've replaced with a static function was derived from PureComponent<T>, which means that each MessageRow instantiation also involved an instantiation of a generic base class. Clearly something is still taking up a lot time.. since the CommonProps<T> class used for MessageRow props was a generic type, maybe it's something specifically to do with generic types.

public static class App
{
    [Ready]
    public static void Main()
    {
        var x = new MyClass<string>[10000];
        var timer = Stopwatch.StartNew();
        for (var i = 0; i < x.Length; i++)
            x[i] = new MyClass<string>("test");
        timer.Stop();
        Console.WriteLine(timer.ElapsedMilliseconds + "ms");
    }
}

public class MyClass<T>
{
    public MyClass(T value)
    {
        Value = value;
    }
    public T Value { get; private set; }
}

This time it reported 35ms. Still not an earth-shattering duration in isolation but a big step up from the non-generic class' 3ms.

One of the nice things about Bridge is that it allows you to tweak the way that the JavaScript is generated. By default, it will strike a good balance between creating reasonable JavaScript while also creating code that is faithful to the C# representation. For example, the MyClass<T> class will get the following JavaScript definition:

Bridge.define('Demo.MyClass$1', function (T) { return {
    config: {
        properties: {
            Value: Bridge.getDefaultValue(T)
        }
    },
    constructor: function (value) {
        this.setValue(value);
    }
}; });

It's important that the type param "T" be available as a reference at runtime in case you ever need to access it (such as via a call to "default(T)" or when needing to instantiate another generic type whose type param will also be "T"). If the type "T" was not known to the runtime then it wouldn't be possible for the JavaScript code to do things like create a "default(T)" value appropriate to whatever "T" is; it should be null for a reference type, zero for a numeric type and false for a boolean.

However, this creation of a class that encapsulates the type parameters must incur some overhead. For comparison, the non-generic class is defined in JavaScript with the following (note the lack of the function that captures "T") -

Bridge.define('Demo.MyClass', {
    config: {
        properties: {
            Value: null
        }
    },
    constructor: function (value) {
        this.setValue(value);
    }
});

One of the options that Bridge has to affect what JavaScript is emitted is the [IgnoreGeneric] attribute. If this is applied to a class then it won't be given a JavaScript definition that includes the type parameter. This means that we can create a generic C# class (and continue to fully take advantage of the safety of the C# type system) but have Bridge generate a cheaper-to-instantiate JavaScript representation.

There is one problem with this, though. The C# code:

[IgnoreGeneric]
public class MyClass<T>
{
    public MyClass(T value)
    {
        Value = value;
    }
    public T Value { get; private set; }
}

will result in the following JavaScript:

Bridge.define('Demo.MyClass$1', {
    config: {
        properties: {
            Value: Bridge.getDefaultValue(T)
        }
    },
    constructor: function (value) {
        this.setValue(value);
    }
});

All properties are set to default values before any instances are created. This is important for cases where there are constructors where one or more properties are not explicitly set since they can't be left undefined. In C#, if you don't set a property on a class instance then it will be left as its default value (null for a reference type, zero for a number, etc..) and Bridge has to maintain this behaviour in JavaScript in order to be consistent. The problem here is that the type "T" is not available and so the "Value" property can't reliably be set to the correct default value.

Since I'm considering tweaking the CommonProps<T> class, this doesn't apply - every property will explicitly be set in the constructor and so I don't have to worry about the case of a property needing to be left with the default value for the type.

Thankfully, Bridge has another way to control the JavaScript that will be helpful. The [Template] attribute may be applied to property getters and setters and will change how these are represented. The default is for "setValue(x)" and "getValue()" methods to be created on the class (this may be seen in the above code, where "this.setValue(value)" is called in the constructor). If the getter is marked with [Template("value")] then anywhere that would previously have called "getValue()" will now simply access "value" and if the setter is marked with [Template("this.value")] then the property-setting (which only happens in the constructor for CommonProps<T>) will not be a call to "setValue", it will simply set "this.value".

To apply this to the MyClass<T> class, the following C#:

[IgnoreGeneric]
public class MyClass<T>
{
    public MyClass(T value)
    {
        Value = value;
    }
    public T Value { [Template("value")]get; [Template("this.value")]private set; }
}

would result in the following JavaScript:

Bridge.define('Demo.MyClass$1', {
    constructor: function (value) {
        this.value = value;
    }
});

Note that the set-properties-to-default-values code is no longer present in the JavaScript class definition.

Also, it's worth noting that this will affect anywhere that the property is accessed by code outside of the class. For example, if there is C# like this:

var x = new MyClass<string>("test");
Console.WriteLine(x.Value);

.. then, instead of the property being accessed through a getter method -

var x = new Demo.MyClass$1("test");
Bridge.Console.log(x.getValue());

.. it will be accessed directly -

var x = new Demo.MyClass$1("test");
Bridge.Console.log(x.value);

This means that the JavaScript is a slightly less faithful representation of the C# code. However, the C# compiler is complete unaware of these changes and it will continue to enforce the type system in the same way that it always does. So (presuming you are writing all of your front end code in C#, using Bridge) you are not losing anything. In fact, there will be some more performance gains to be had by accessing properties directly like this - there is a small overhead to calling functions to return values (small, but not zero) as opposed to retrieving them directly.

If this is applied to CommonProps<T> then we get the following:

[IgnoreGeneric]
public sealed class CommonProps<T>
{
    public CommonProps(
        T state,
        Action<T> onChange,
        Optional<ClassName> className,
        bool disabled,
        Optional<Any<string, int>> key)
    {
        if (state == null)
            throw new ArgumentNullException("state");
        if (onChange == null)
            throw new ArgumentNullException("onChange");

        State = state;
        OnChange = onChange;
        ClassName = className;
        Disabled = disabled;
        Key = key;
    }

    public T State
    {
        [Template("state")]get; [Template("this.state")]private set;
    }
    public Action<T> OnChange
    {
        [Template("onChange")]get; [Template("this.onChange")]private set;
    }
    public Optional<ClassName> ClassName
    {
        [Template("className")]get; [Template("this.className")]private set;
    }
    public bool Disabled
    {
        [Template("disabled")]get; [Template("this.disabled")]private set;
    }
    public Optional<Any<string, int>> Key
    {
        [Template("key")]get; [Template("this.key")]private set;
    }
}

In order to do this, CommonProps<T> could no longer be an IAmImmutable type since the "CtorSet" and "With" methods won't work with properties that rely upon any fancy shenanigans like [Template]. This isn't a huge deal with the props on components since they are always created fresh for every render, unlike the other data types that represent state. For example, when the title value of a single row is edited, a new MessageEditState instance is created using something like the following:

newMessage = currentMessage.With(_ => _.Title, newTitle)

This is important for two reasons. Firstly, if "newTitle" is the same as the current title (which can happen if the user does something to a text box that doesn't actually change its value - such as when pasting a value into the box that is the same as the current value; React will identify this as an input change even though the value hasn't actually been altered) then a new message instance is not created. When the MessageRow is re-rendered, because the MessageEditState reference won't have changed, the PureComponent logic will tell React that there is no need to re-render the row, which saves React some work. Secondly, it's very convenient to be able to get a new instance of a data type with a single property changed in this manner - otherwise you would have to deal with the has-this-value-really-changed logic and either define "With{x}" methods for each individual property or call the constructor with the value that has changed and all of the ones that haven't. Which gets old very quickly. (You could use mutable data types but then you wouldn't be able perform inexpensive reference equality checks when trying to determine whether a component needs to re-render and so you end up contemplating expensive deep equality checks or you give up on implementing "shouldComponentUpdate" and force React to do much more work).

One final note: the CtorSet method that IAmImmutable types can use ensures that no value is ever null (if you have a property that may or may not have a value then use the Optional<T> type - which can never be null itself since it's a struct). Since CommonProps<T> isn't using CtorSet any more, the constructor needs to include explicit checks for null "state" and "onChange" constructor arguments.

With this change to CommonProps<T>, the "Render" time is now 124ms in the React development build. Interestingly, in the React production, the "Render" time is reduced to 69ms and the "receiveComponent" drops to 98ms. A combined 167ms is much better than the original 838ms.

With these improvements, there is only a slightly perceptible delay felt when clicking a checkbox. Unfortunately, though, trying to type into a text box when there is a 167ms delay between key presses being recognised is not pleasant. So it's back to the profiler..

Optional<T>

Taking another snapshot with the profiler, I'm still going to concentrate on the "Render" method (for the same reasons as before; it's still the slower part of the work and it's still what I can most easily control). This time I see a lot of calls to a generic constructor resulting from "op_Implicit" calls.

Unnecessary Optional instantiation

The "op_Implicit" methods are the JavaScript representations of implicit operator methods in C#. So, where the Optional<T> struct has an implicit operator from "T" -

public static implicit operator Optional<T>(T value)
{
    return new Optional<T>(value);
}

the following JavaScript is generated:

op_Implicit: function (value) {
    return new (ProductiveRage.Immutable.Optional$1(T)).$constructor1(value);
}

When a CommonProps instance is created with a null "className" argument (which is the case for every MessageRow in the sample app), each call to the CommonProps "For" method requires the null reference to be implicitly cast to an Optional<ClassName>.

public static CommonProps<T> For<T>(
    T state,
    Action<T> onChange,
    Optional<ClassName> className,
    bool disabled,
    Any<string, int> key)

Each implicit cast requires a call to the implicit operator, which creates a new Optional<ClassName> instance. This feels like unnecessary work.

The Optional<T> has a public static "Missing" property, so one way to avoid the creation of unnecessary instances would be to use

className: Optional<ClassName>.Missing

instead of

className: null

But there were a few problems with this. Firstly, Optional<T> is part of the ProductiveRage.Immutable library and I would like it to be as easy to use as possible. I think that it would be quite difficult to justify a significant performance cost in passing null as an Optional rather than "Missing" when there is an implicit cast to perform the translation. Secondly, the "Missing" property was implemented as

    public static Optional<T> Missing { get { new Optional<T>(default(T), false); } }

.. which means that a new instance is created each time it's called anyway, so actually the "Missing" property wouldn't magically solve anything.

It would make more sense for the "Missing" property to be set only once, something like:

public static Optional<T> Missing { get { return _missing; } }
private static Optional<T> _missing = new Optional<T>(default(T), false);

When I first wrote the Optional<T> struct, that is how I did it. Unfortunately, there was a problem with Bridge 1.10 and I removed the private "_missing" field as a workaround. The Bridge Team have long since resolved that issue and so I can put the code back how I want it.

This also allows for a tweak to the implicit operator method -

public static implicit operator Optional<T>(T value)
{
    if (value == null)
        return _missing;
    return new Optional<T>(value);
}

Now, one might presume, there would now be no unnecessary instantiations whether "className: Optional<ClassName>.Missing" or "className: null" was specified. Unfortunately, we're not quite there yet..

When structs are passed around in C#, they are copied. This is why they appear to be passed "by value" rather than "by reference" - if a mutable struct is instantiated in method F1 and passed to F2, any changes made to it in F2 are not visible in F1 since they both have different copies of the struct. To ensure consistency with .net, Bridge's JavaScript must do something similar - any time that a struct is passed around, it is copied. This means that a new instance will be created each time that "Missing" or "_missing" is accessed. This is wasteful with the Optional<T> struct since it's immutable; since nothing can alter its contents, there is no need to copy it when passing it around.

Bridge has another workaround for this, the [Immutable] attribute. When applied to the Optional<T> struct, the Bridge compiler will not copy instances when they are passed from one method to another. These changes reduce the "Render" time to 93ms in the React development build and 61ms in production.

While this is an improvement, I can still see what looks like a lot of time spent on generic type stuff in the profiler. Even though the op_Implicit calls for null values are sharing instances now, in order to get to the static op_Implicit method it is necessary to access the representation of the Optional<T> struct for the particular type. And, I suspect, this incurs a similar cost to instantiating a new instance.

To confirm this, I added [IgnoreGeneric] to Optional<T>. This was not something I really wanted to do since it would require a minor change to the struct's public interface. There are two properties; IsDefined and Value. Currently there are two states - a state where IsDefined is true and Value has a specified "T" value and a state where IsDefined is false and Value has the default value of "T" (null for a reference type, zero for a number). With the [IgnoreGeneric] attribute, it would not be possible to set the default value of "T" for the "Missing" value state since "T" would not be available at runtime. If I was to apply [IgnoreGeneric] to the struct then "Value" would have to be considered undefined if IsDefined was false. This isn't a huge deal since I think that that's how it should have been interpreted anyway, really (an alternative would have been to be more aggressive and throw an exception from the Value property getter if IsDefined is false) but it's still a change.

When I added [IgnoreGeneric] to the CommonProps<T> class, I had to apply some workarounds to deal with the type "T" not being available at runtime. I had to do similar with Optional<T>. The first change was that the following line clearly wouldn't work:

private static Optional<T> _missing = new Optional<T>(default(T), false);

so it was replaced with this:

private static Optional<T> _missing = new Optional<T>(Script.Write<T>("null"), false);

The "Script.Write<T>" method in Bridge is a way to directly emit JavaScript (simply "null" in this case) and to tell the C# type system that a value of type "T" is being returned. So, here, the "T" is only used by the C# compiler and does not have any impact on runtime. The compromise is that "null" is being used for the Value property of the "Missing" instance regardless of the type of "T". So Value will be null even if "T" is an int or a bool in cases where IsDefined is false.

The other change required completely removing the C# backing field for the Value property -

private readonly T value;

The problem was that Bridge would generate a struct definition that would try to set "value" to default(T), which it would not be able to do since "T" would not be available at runtime.

Instead, the value would be written directly by more raw JavaScript. The constructor changed from:

public Optional(T value) : this(value, value != null) { }
    this.isDefined = isDefined && (value != null);
    this.value = value;
}

to:

public Optional(T value) : this(value, value != null) { }
    this.isDefined = isDefined && (value != null);
    Script.Write("this.value = {0}", value);
}

and the property getter changed from:

public T Value { get { return this.value; } }

to:

public T Value { get { return Script.Write<T>("this.value"); } }

Finally, anywhere in the struct that the backing field was accessed was changed so that it went via the public "Value" property getter.

This meant that there were no potential runtime errors waiting to occur within the struct (none of the code relied on access to the type "T"), that there was type safety for any code instantiating or accessing the struct in C# and it meant that the struct could have [IgnoreGeneric] applied and hence (theoretically) allow the application to work more efficiently.

It worked. Using the development build of React, the "Render" time of the MessageTable was now 36ms and the "receiveComponent" time 141ms. With the production build, "Render" took "9ms" and "receiveComponent" 49ms.

That's sufficiently fast that there is no perceived delay while typing into the text boxes. And, to put things back into context, the original "worst case scenario" that I was planning for was to deal with up to 1,000 checkboxes. I've been measuring the time for 5,000 rows that include two text boxes and a checkbox. If the sample app was changed to render only 1,000 rows then the React production build handles changes to elements by spending 5ms in "Render" and 17ms in "receiveComponent". This means that there is no chance of perceptible lag in typing and certainly no perceptible delay in checking or unchecking a checkbox.

To summarise

I think that it's fair to call this a success! There are several things that I've particularly enjoyed in this investigation. Firstly, it's been a good reminder of just how powerful the dev tools are that come free with browsers these days. I was using Chrome but I believe that IE and Firefox have equivalent functionality. Secondly, the options that the Bridge Team have made available are really well thought out and very clever when you examine them - in isolation, each seems quite simple but it's the recognition that sometimes it might be beneficial to have more control over the generated JavaScript that helps make Bridge so powerful and to enable me to do what I've done here. Thirdly, almost all of the changes that I've talked about here were made to my "Bridge.React", "ProductiveRage.Immutable", "ProductiveRage.Immutable.Extensions" libraries. That means that, when I make these changes live, anyone using those libraries will automatically reap the benefit. The only change that I made to the sample app was to change the MessageRow implementation from being a component class to being a static function.

Note: I tried reverting MessageRow back to being a component class and the "Render" time was still only 20ms when editing one of 1,000 rows (compared to 5ms when MessageRow is implemented as a static function). The time spent by React in "receiveComponent" was unaffected. This means that simply updating the Bridge.React, ProductiveRage.Immutable and ProductiveRage.Immutable.Extensions packages could significantly improve the performance of complex applications with zero code changes.

This is one of the benefits of using libraries where the authors care about performance and strive to improve it over time. It reminds me of when the Bridge Team added compiler support for "Lifted Anonymous Functions" (something I suggested after going on a bit of a JavaScript performance research binge a few months ago - but something that the team there deserve much credit for making work) and it reminds me of articles that I've read about React which talk about how there are many optimisations yet to be made that their current API will make possible (see "React Fiber Architecture"); all that we'll have to do in the future is upgrade the version of the library being used and get more performance!

Update: The Bridge Team ruin my fun

I've been researching and writing this post over the space of a couple of weeks. Once I had observed that generic classes are slower to instantiate in Bridge than non-generic classes, and while I was looking into the workarounds required sometimes in order to use [IgnoreGeneric], I raised a bug on the Bridge Forums relating to properties that are initially to default(T) (which fails when "T" is not available at runtime).

While looking into the issue for me, they noted that they found a way to optimise the instantiation of generic types (looking at the pull request it seems like the work required to form a new specialisation of a class / struct for a given "T" is now cached rather than being repeated each time that a new Whatever<T> is created).

The good news is that this means that there will very soon be almost zero overhead to generic types in Bridge! The bad news is that many of the findings documented here are unnecessary.. However, that's the sort of bad news that I'm happy to accept! The compromise around Optional<T>'s "Value" property (for cases where "IsDefined" is false) will no longer be necessary. And I won't have to worry so much in the future; if I'm creating a library class, should I be avoiding generics (or using [IgnoreGeneric]) in case it's used in an expensive loop anywhere?

Despite being out of date even before being published, I'll leave this post here for posterity. I had a lot of fun digging into performance tuning my Bridge / React app. And, in a roundabout way, I feel like I contributed to the optimisation (which I imagine will makes its way into the next release of Bridge) that everyone using Bridge can benefit from! I'm going to call that a win.

Posted at 22:04

Comments

Using Roslyn code fixes to make the "Friction-less immutable objects in Bridge" even easier

This is going to be a short post about a Roslyn (or "The .NET Compiler Platform", if you're from Microsoft) analyser and code fix that I've added to a library. I'm not going to try to take you through the steps required to create an analyser nor how the Roslyn object model describes the code that you've written in the IDE* but I want to talk about the analyser itself because it's going to be very useful if you're one of the few people using my ProductiveRage.Immutable library. Also, I feel like the inclusion of analysers with libraries is something that's going to become increasingly common (and I want to be able to have something to refer back to if I get the chance to say "told you!" in the future).

* (This is largely because I'm still struggling with it a bit myself; my current process is to start with Use Roslyn to Write a Live Code Analyzer for Your API and the "Analyzer with Code Fix (NuGet + VSIX)" Visual Studio template. I then tinker around a bit and try running what I've got so far, so that I can use the "Syntax Visualizer" in the Visual Studio instance that is being debugged. Then I tend to do a lot of Google searches when I feel like I'm getting close to something useful.. how do I tell if a FieldDeclarationSyntax is for a readonly field or not? Oh, good, someone else has already written some code doing something like what I want to do - I look at the "Modifiers" property on the FieldDeclarationSyntax instance).

As new .net libraries get written, some of them will have guidelines and rules that can't easily be described through the type system. In the past, the only option for such rules would be to try to ensure that the documentation (whether this be the project README and / or more in-depth online docs and / or the xml summary comment documentation for the types, methods, properties and fields that intellisense can bring to your attention in the IDE). The support that Visual Studio 2015 introduced for customs analysers* allows these rules to be communicated in a different manner.

* (I'm being English and stubborn, hence my use of "analysers" rather than "analyzers")

In short, they allow these library-specific guidelines and rules to be highlighted in the Visual Studio Error List, just like any error or warning raised by Visual Studio itself (even refusing to allow the project to be built, if an error-level message is recorded).

An excellent example that I've seen recently was encountered when I was writing some of my own analyser code. To do this, you can start with the "Analyzer with Code Fix (NuGet + VSIX)" template, which pulls in a range of NuGet packages and includes some template code of its own. You then need to write a class that is derived from DiagnosticAnalyzer. Your class will declare one of more DiagnosticDescriptor instances - each will be a particular rule that is checked. You then override an "Initialize" method, which allows your code to register for syntax changes and to raise any rules that have been broken. You must also override a "SupportedDiagnostics" property and return the set of DiagnosticDescriptor instances (ie. rules) that your analyser will cover. If the code that the "Initialize" method hooks up tries to raise a rule that "SupportedDiagnostics" did not declare, the rule will be ignored by the analysis engine. This would be a kind of (silent) runtime failure and it's something that is documented - but it's still a very easy mistake to make; you might create a new DiagnosticDescriptor instance and raise it from your "Initialize" method but forget to add it to the "SupportedDiagnostics" set.. whoops. In the past, you may not realise until runtime that you'd made a mistake and, as a silent failure, you might end up getting very frustrated and be stuck wondering what had gone wrong. But, mercifully (and I say this as I made this very mistake), there is an analyser in the "Microsoft.CodeAnalysis.CSharp" NuGet package that brings this error immediately to your attention with the message:

RS1005 ReportDiagnostic invoked with an unsupported DiagnosticDescriptor

The entry in the Error List links straight to the code that called "context.ReportDiagnostic" with the unexpected rule. This is fantastic - instead of suffering a runtime failure, you are informed at compile time precisely what the problem is. Compile time is always better than run time (for many reasons - it's more immediate, so you don't have to wait until runtime, and it's more thorough; a runtime failure may only happen if a particular code path is followed, but static analysis such as this is like having every possible code path tested).

The analysers already in ProductiveRage.Immutable

The ProductiveRage uber-fans (who, surely exist.. yes? ..no? :D) may be thinking "doesn't the ProductiveRage.Immutable library already have some analysers built into it?"

And they would be correct, for some time now it has included a few analysers that try to prevent some simple mistakes. As a quick reminder, the premise of the library is that it will make creating immutable types in Bridge.NET easier.

Instead of writing something like this:

public sealed class EmployeeDetails
{
  public EmployeeDetails(PersonId id, NameDetails name)
  {
    if (id == null)
      throw new ArgumentNullException("id");
    if (name == null)
      throw new ArgumentNullException("name");

    Id = id;
    Name = name;
  }

  /// <summary>
  /// This will never be null
  /// </summary>
  public PersonId Id { get; }

  /// <summary>
  /// This will never be null
  /// </summary>
  public NameDetails Name { get; }

  public EmployeeDetails WithId(PersonId id)
  {
    return Id.Equals(id) ? this : return new EmployeeDetails(id, Name);
  }
  public EmployeeDetails WithName(NameDetails name)
  {
    return Name.Equals(name) ? this : return new EmployeeDetails(Id, name);
  }
}

.. you can express it just as:

public sealed class EmployeeDetails : IAmImmutable
{
  public EmployeeDetails(PersonId id, NameDetails name)
  {
    this.CtorSet(_ => _.Id, id);
    this.CtorSet(_ => _.Name, name);
  }
  public PersonId Id { get; }
  public NameDetails Name { get; }
}

The if-null-then-throw validation is encapsulated in the CtorSet call (since the library takes the view that no value should ever be null - it introduces an Optional struct so that you can identify properties that may be without a value). And it saves you from having to write "With" methods for the updates as IAmImmutable implementations may use the "With" extension method whenever you want to create a new instance with an altered property - eg.

var updatedEmployee = employee.With(_ => _.Name, newName);

The library can only work if certain conditions are met. For example, every property must have a getter and a setter - otherwise, the "CtorSet" extension method won't know how to actually set the value "under the hood" when populating the initial instance (nor would the "With" method know how to set the value on the new instance that it would create).

If you forgot this and wrote the following (note the "DisplayNameLength" property that is now effectively a computed value and there would be no way for us to directly set it via a "With" call) -

public sealed class EmployeeDetails : IAmImmutable
{
  public EmployeeDetails(PersonId id, NameDetails name)
  {
    this.CtorSet(_ => _.Id, id);
    this.CtorSet(_ => _.Name, name);
  }
  public PersonId Id { get; }
  public NameDetails Name { get; }
  public int DisplayNameLength { get { return Name.DisplayName.Length; } }
}

.. then you would see the following errors reported by Visual Studio (presuming you are using 2015 or later) -

Example analyser errors raised by the ProductiveRage.Immutable library

.. which is one of the "common IAmImmutable mistakes" analysers identifying the problem for you.

Getting Visual Studio to write code for you, using code fixes

I've been writing more code with this library and I'm still, largely, happy with it. Making the move to assuming never-allow-null (which is baked into the "CtorSet" and "With" calls) means that the classes that I'm writing are a lot shorter and that type signatures are more descriptive. (I wrote about all this in my post at the end of last year "Friction-less immutable objects in Bridge (C# / JavaScript) applications" if you're curious for more details).

However.. I still don't really like typing out as much code for each class as I have to. Each class has to repeat the property names four times - once in the constructor, twice in the "CtorSet" call and a fourth time in the public property. Similarly, the type name has to be repeated twice - once in the constructor and once in the property.

This is better than the obvious alternative, which is to not bother with immutable types. I will gladly take the extra lines of code (and the effort required to write them) to get the additional confidence that a "stronger" type system offers - I wrote about this recently in my "Writing React with Bridge.NET - The Dan Way" posts; I think that it's really worthwhile to bake assumptions into the type system where possible. For example, the Props types of React components are assumed, by the React library, to be immutable - so having them defined as immutable types represents this requirement in the type system. If the Props types are mutable then it would be possible to write code that tries to change that data and then bad things could happen (you're doing something that library expects not to happen). If the Props types are immutable then it's not even possible to write this particular kind of bad-things-might-happen code, which is a positive thing.

But still I get a niggling feeling that things could be better. And now they are! With Roslyn, you can not only identify particular patterns but you can also offer automatic fixes for them. So, if you were to start writing the EmployeeDetails class from scratch and got this far:

public sealed class EmployeeDetails : IAmImmutable
{
  public EmployeeDetails(PersonId id, NameDetails name)
  {
  }
}

.. then an analyser could identify that you were writing an IAmImmutable implementation and that you have an empty constructor - it could then offer to fix that for you by filling in the rest of the class.

The latest version of the ProductiveRage.Immutable library (1.7.0) does just that. The empty constructor will not only be identified with a warning but a light bulb will also appear alongside the code. Clicking this (or pressing [Ctrl]-[.] while within the empty constructor, for fellow keyboard junkies) will present an option to "Populate class from constructor" -

Screenshot showing the analyser identifying an empty constructor on an IAmImmutable implementation

Selecting the "Populate class from constructor" option -

Screenshot showing the code fix that may auto-populate the incomplete IAmImmutable implementation

.. will take the constructor arguments and generate the "CtorSet" calls and the public properties automatically. Now you can have all of the safety of the immutable type with no more typing effort than the mutable version!

// This is what you have to type of the immutable version,
// then the code fix will expand it for you
public sealed class EmployeeDetails : IAmImmutable
{
  public EmployeeDetails(PersonId id, NameDetails name)
  {
  }
}

// This is what you would have typed if you were feeling
// lazy and creating mutable types because you couldn't
// be bothered with the typing overhead of immutability
public sealed class EmployeeDetails
{
  public PersonId Id;
  public NameDetails name;
}

To summarise

If you're already using the library, then all you need to do to start taking advantage of this code fix is update your NuGet reference* (presuming that you're using VS 2015 - analysers weren't supported in previous versions of Visual Studio).

* (Sometimes you have to restart Visual Studio after updating, you will know that this is the case if you get a warning in the Error List about Visual Studio not being able to load the Productive.Immutable analyser)

If you're writing your own library that has any guidelines or common gotchas that you have to describe in documentation somewhere (that the users of your library may well not read unless they have a problem - at which point they may even abandon the library, if they're only having an investigative play around with it) then I highly recommend that you consider using analysers to surface some of these assumptions and best practices. While I'm aware that I've not offered much concrete advice on how to write these analysers, the reason is that I'm still very much a beginner at it - but that puts me in a good position to be able to say that it really is fairly easy if you read a few articles about it (such as Use Roslyn to Write a Live Code Analyzer for Your API) and then just get stuck in. With some judicious Google'ing, you'll be making progress in no time!

I guess that only time will tell whether library-specific analysers become as prevalent as I imagine. It's very possible that I'm biased because I'm such a believer in static analysis. Let's wait and see*!

* Unless YOU are a library writer that this might apply to - in which case, make it happen rather than just sitting back to see what MIGHT happen! :)

Posted at 22:33

Comments

Writing React apps using Bridge.NET - The Dan Way (Part Three)

In parts One and Two, I described how to create a simple application using React and a Flux-like architecture, written in Bridge.NET - it covered where and how to deal with validation, how to integrate with a persistence layer, how to deal with asynchronous interactions (and how they don't need to be scary) and how the approach made the code easy to test and easy to reason about.

The components created using the React / Bridge bindings have their requirements / dependencies described in a strongly-typed manner since each component's "props" reference is a nested class with properties for each value or reference that will be needed in order for it to render.

This combination of technologies has the potential to be really powerful for writing client-side / browser-based applications, particularly with the ability to leverage C#'s proven strength in allowing the writing of large and reliable systems. However, I'm not happy with the example application yet. Although the way that it's written makes a lot of it easy to understand and, hopefully, makes the intent of the code clear, it still could be even easier to understand and the intent and the requirements even clearer.

People often like to talk as if a language is dynamically-typed (or "non-typed" or "uni-typed", depending upon the language, their vocabulary and their knowledge and opinion of the language) or statically-typed; as if it is a binary choice. Really, it is a sliding scale. C# definitely sits on the "statically-typed side", but the way that you write C# dictates how far along the scale that your C# is.

(C# can also be written to act as a dynamically-typed language, particularly if you use the "dynamic" keyword - but it's principally a statically-typed language).

I'm going to describe some ways to improve the example application and, in doing so, extrapolate some rules as to how to make the code clearer (and, again, easier to reason about, write and maintain - since these are extremely important qualities of code to me, that I strive for when developing and that appealed to me when I first encountered React). These will be my opinions (based upon my experiences) and you might disagree with them - but this is where we really get into "The Dan Way" of working with Bridge and React. If you do choose to disagree, then hopefully parts One and Two will continue to be useful (but I'm afraid we can never be friends*).

* (Only joking**)

** (I'm not)

Clarification through a richer type system

Let's jump straight in with a simple example. We have a TextInput component that renders a text input element and passes up any requests by the user that the input's content be changed. The main primary purpose of this class is to provide a simple interface. Many of the html attributes that may be applied to a text input are not relevant (this exposes only the basics, such as "ClassName"). Similarly, the "OnChange" that a text input raises has a relatively complicated event reference (it allows you to identify the element that changed and then get the requested "new value" from it, but I want a TextInput's "OnChange" event to simply provide the new string and nothing else).

using System;
using Bridge.Html5;
using Bridge.React;

namespace BridgeReactTutorial.Components
{
  public class TextInput : StatelessComponent<TextInput.Props>
  {
    public TextInput(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.Input(new InputAttributes
      {
        Type = InputType.Text,
        ClassName = props.ClassName,
        Disabled = props.Disabled,
        Value = props.Content,
        OnChange = e => props.OnChange(e.CurrentTarget.Value)
      });
    }

    public class Props
    {
      public string ClassName;
      public bool Disabled;
      public string Content;
      public Action<string> OnChange;
    }
  }
}

In the context of this small class, looking at the code, I would say that it's fairly clear what each line of code does and what each of the properties of the Props class is required for and how it will be used. However, even within such a small class, there are several implicit assumptions that are being made - eg.

  1. ClassName is optional, it may be null.. or it may be blank - React will actually treat these two cases differently, do we really want that? If it's null then no "class" attribute will be present on the input element, but if it's blank then a "class" attribute will be added (but with no value).
  2. Content is treated in the same way but probably shouldn't be - does it really make sense for Content to potentially be null? Blank, yes; if there's no user-entered content. But null? Probably not.
  3. OnChange is not optional - if it's null then a null reference exception is going to be thrown when the user attempts to change the value in the input box (because "props.OnChange" will be called like a function, which will fail if it's null).

First off, I don't like the should-or-shouldn't-be-allowed-to-be-null confusion around the "ClassName" and "Content" values. Secondly, I don't like the fact that, as it stands, you need to read (or already be familiar with) the code inside the TextInput component. One way to try to address these issues would be to consider using summary comments on the Props class - eg.

public class Props
{
  /// <summary>
  /// This is optional and so may be null (if non-null, then it should be a valid class
  /// name - ie. non-blank)
  /// </summary>
  public string ClassName;

  public bool Disabled;

  /// <summary>
  /// An input may not always have a value and so this may be blank (but it should never
  /// be null)
  /// </summary>
  public string Content;

  /// <summary>
  /// This is mandatory and may never be null
  /// </summary>
  public Action<string> OnChange;
}

The problem with this approach is that, if the comments are ignored, runtime problems will occur at some point and it may not be very easy to trace them back to where they originated. If the "OnChange" value is null, for example, then the problem won't be noticed until the user interacts with the input box - and the code that raises the exception (the "props.OnChange" call with TextInput's "Render" method) will be completely removed from the code that incorrectly set the null value (the code that instantiated and populated Props instance).

So another alternative would be to combine these comments with some validation - eg.

public class Props
{
  private string _className, _content;
  private Action<string> _onChange;

  /// <summary>
  /// This is optional and so may be null (if non-null, then it should be a valid class
  /// name - ie. non-blank)
  /// </summary>
  public string ClassName
  {
    get { return _className; }
    set
    {
      if (value == "")
        throw new ArgumentException("ClassName should not be set to a blank string");
      _className = value;
    }
  }

  public bool Disabled { get; set; }

  /// <summary>
  /// An input may not always have a value and so this may be blank (but it should never
  /// be null)
  /// </summary>
  public string Content
  {
    get { return _content; }
    set
    {
      if (value == null)
        throw new ArgumentNullException("Content should not be set to null");
      _content = value;
    }
  }

  /// <summary>
  /// This is mandatory and may never be null
  /// </summary>
  public Action<string> OnChange
  {
    get { return _onChange; }
    set
    {
      if (value == null)
        throw new ArgumentNullException("OnChange should not be set to null");
      _onChange = value;
    }
  }
}

This way, it would not be possible to explicitly set "OnChange" to null - if this was attempted then an exception would be thrown immediately, right at the point in the code that was attempting to assign this invalid value. This is much better than it failing later on, at some point that depends upon how the user does or doesn't interact with the UI component. This is potentially the sort of mistake that goes unnoticed for some time. For cases that are clearly a "programmer error" bug like this, I much prefer to "fail fast".

There's still a problem, though, because the initial state of the Props class is invalid, since "OnChange" will start as null. If the initialisation code explicitly tries to set it to null then it will fail fast, but if it doesn't set it at all then it remain null and we'll be back to where we started in terms of where and when the exception is raised compared to where the programming mistake was made.

Attempt three could be to set appropriate defaults - eg.

public class Props
{
  private string _className = null;
  private string _content = "";
  private Action<string> _onChange = newValue => { };

  /// <summary>
  /// This is optional and so may be null (if non-null, then it should be a valid class
  /// name - ie. non-blank)
  /// </summary>
  public string ClassName
  {
    get { return _className; }
    set
    {
      if (value == "")
        throw new ArgumentException("ClassName should not be set to a blank string");
      _className = value;
    }
  }

  public bool Disabled { get; set; }

  /// <summary>
  /// An input may not always have a value and so this may be blank (but it should never
  /// be null)
  /// </summary>
  public string Content
  {
    get { return _content; }
    set
    {
      if (value == null)
        throw new ArgumentNullException("Content should not be set to null");
      _content = value;
    }
  }

  /// <summary>
  /// This is mandatory and may never be null
  /// </summary>
  public Action<string> OnChange
  {
    get { return _onChange; }
    set
    {
      if (value == null)
        throw new ArgumentNullException("OnChange should not be set to null");
      _onChange = value;
    }
  }
}

Now it's not possible for "OnChange" to be null, so a null reference exception can not be thrown when the user tries to interact with the component.

This still isn't fantastic, though. Is it really likely that there's ever a time where no "OnChange" value should have been set? Changes are that, in that case, there is still a programmer error (a TextInput is useless without an "OnChange" callback and so one should be set).. but now the error is being silently swallowed.

So, maybe most properties should have to be specified in order to get a new Props instance. Since values have to be provided at the point of initialisation, they may as well be validated at that point. This is a very good argument for making the Props class immutable - eg.

public class Props
{
  public Props(string className, string content, bool disabled, Action<string> onChange)
  {
    if (className == "")
      throw new ArgumentException("className should not be set to a blank string");
    if (content == null)
      throw new ArgumentNullException("content");
    if (onChange == null)
      throw new ArgumentNullException("onChange");

    ClassName = className;
    Content = content;
    Disabled = disabled;
    OnChange = onChange;
  }

  /// <summary>
  /// This is optional and so may be null (if non-null, then it will never be blank)
  /// </summary>
  public string ClassName { get; }

  public bool Disabled { get; }

  /// <summary>
  /// An input may not always have a value and so this may be blank (but it should never
  /// be null)
  /// </summary>
  public string Content { get; }

  /// <summary>
  /// This is mandatory and will never be null
  /// </summary>
  public Action<string> OnChange { get; }
}

Two nice benefits arise from this. Firstly, the comments may be tightened up - so "OnChange" is no longer described as

This is mandatory and should never be null

now it is

This is mandatory and will never be null

It's a seemingly small change, but I'm looking for confidence in the code and this is a positive step from "hopefully this won't happen" to "this can not happen (because an ArgumentNullException would have been instantly thrown if an attempt was made to create a Props instance in this manner)".

The second benefit is that the Props class now communicates one of the React guidelines - the React documentation states that props data should be considered immutable; once a component has a props reference, it should not try to change its data, nor should it expect any other code to be able to change it. Now, that commandment is baked into the code - this is a great example of what I mean when I talk about using a "richer type system", there's more information that may be encoded than just "this class has a property that is of type string".

One final tweak to this sort of approach is to enable optional values to truly be optional. In this example, I'm talking about "className". The constructor may be changed from:

public Props(string className, string content, bool disabled, Action<string> onChange)
{
  if (className == "")
    throw new ArgumentException("className should not be set to a blank string");
  if (content == null)
    throw new ArgumentNullException("content");
  if (onChange == null)
    throw new ArgumentNullException("onChange");

  ClassName = className;
  Content = content;
  Disabled = disabled;
  OnChange = onChange;
}

to:

public Props(string content, bool disabled, Action<string> onChange, string className = "")
{
  if (content == null)
    throw new ArgumentNullException("content");
  if (onChange == null)
    throw new ArgumentNullException("onChange");
  if (className == "")
    throw new ArgumentException("className should not be set to a blank string");

  Content = content;
  Disabled = disabled;
  OnChange = onChange;
  ClassName = className;
}

This means that an instance of TextInput.Props may be created, if no class name is required, like this:

new TextInput.Props(title, isSaveInProgress, onTitleChange)

Or, if a class name is required:

new TextInput.Props(title, isSaveInProgress, onTitleChange, "title")

Personally, I like to use named constructor arguments when creating Props instances, so I would probably write:

new TextInput.Props(
  className: "title",
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

I think that this makes the code easier to read (I don't need to resort to looking at the Props constructor to see that "title" is a class name and not an ID or any other use for a string) and means that it doesn't matter that the "className" argument moved from the start of the constructor argument list to the end, since the position of arguments doesn't matter when their names are used. (As an added benefit, this makes the code slightly more similar to the React component initialisation code that you might see in non-Bridge/C# projects, where JSON objects are used to set properties - but, here, we have the added benefit that's it all typed).

This is a big step forward in terms of including additional information in the type system (and in terms of catching errors quickly - and as close to the root cause of the error as possible), meaning that I can more reliably use a component without having to know everything about how it works (which, in a lot of ways, is like the idea of coding against an interface - you want to know about how to communicate with an interface to get the desired result without having to know all of the details of its implementation).

I'm not completely happy with the code at this point, though. It feels like the Props class has ballooned considerably from:

public class Props
{
  public string ClassName;
  public bool Disabled;
  public string Content;
  public Action<string> OnChange;
}

to:

public class Props
{
  public Props(
    string content,
    bool disabled,
    Action<string> onChange,
    string className = "")
  {
    if (content == null)
      throw new ArgumentNullException("content");
    if (onChange == null)
      throw new ArgumentNullException("onChange");
    if (className == "")
      throw new ArgumentException("className should not be set to a blank string");

    Content = content;
    Disabled = disabled;
    OnChange = onChange;
    ClassName = className;
  }

  /// <summary>
  /// This is optional and so may be null (if non-null, then it will never be blank)
  /// </summary>
  public string ClassName { get; }

  public bool Disabled { get; }

  /// <summary>
  /// An input may not always have a value and so this may be blank (but it should never
  /// be null)
  /// </summary>
  public string Content { get; }

  /// <summary>
  /// This is mandatory and will never be null
  /// </summary>
  public Action<string> OnChange { get; }
}

While I am willing to make a certain trade-off between the cost of writing the code to begin with against the long term benefits of it being easier to quickly understand and then reason about*, I don't want to have to write any more of this monotonous form of code than absolutely necessary - in particular, I think I would get bored of writing "This is mandatory and will never be null" over and over again on different properties on different classes**.

* (Since "Code is read much more often than it is written, so plan accordingly", I strongly believe that a little extra writing effort is worth it to reduce the more-often-incurred reading effort).

** (I have personally written a lot of code that uses immutable, always-valid types and that was littered with these sorts of comments - while I definitely think it was worth it, I definitely HAVE gotten bored with writing "This will never be null" time after time after time).

But what alternative is there?

Working on the basis that null is never allowed

Since this whole series is about "The Dan Way", I think that it is entirely reasonable to introduce a library that I've written at this point. It's a NuGet package for Bridge that makes it easier to write immutable types, such as the Props class above: "ProductiveRage.Immutable".

If a class implements an empty interface IAmImmutable then it may access extension methods that make the constructor easier to write. Something along the lines of:

public class Props : IAmImmutable
{
  public Props(string content, bool disabled, Action<string> onChange, string className = "")
  {
    this.CtorSet(_ => _.Content, content);
    this.CtorSet(_ => _.Disabled, disabled);
    this.CtorSet(_ => _.OnChange, onChange);
    this.CtorSet(_ => _.ClassName, className);
  }
  public string ClassName { get; }
  public bool Disabled { get; }
  public string Content { get; }
  public Action<string> OnChange { get; }
}

The extension method is "CtorSet" and it takes a lambda that specifies a property on the class and it takes a new value for that property. The type of the property and the type of the new value must be consistent - so, although there's apparently a little magic involved, we're not sacrificing any type safety.

One interesting feature of "CtorSet" is that it will never allow a null value. This means the comments from the Props class along the lines of "This will never be null" are unnecessary because an IAmImmutable-implementing class that sets all of its properties in its constructor will never have any null property values.

This actually doesn't work for the Props class we're looking at here since we want "ClassName" to be allowed to be null. To enable that, the library comes with a new struct - Optional<T>. Any time that you want to have a constructor argument be null, you have to wrap its type in this struct - ie.

public class Props : IAmImmutable
{
  public Props(
    string content,
    bool disabled,
    Action<string> onChange,
    Optional<string> className = new Optional<string>())
  {
    this.CtorSet(_ => _.Content, content);
    this.CtorSet(_ => _.Disabled, disabled);
    this.CtorSet(_ => _.OnChange, onChange);
    this.CtorSet(_ => _.ClassName, className);
  }
  public Optional<string> ClassName { get; }
  public bool Disabled { get; }
  public string Content { get; }
  public Action<string> OnChange { get; }
}

Once again, we've made a step forward to encoding additional information in the class itself. In terms of being able to more easily reason about the code, this is a great win - classes such as these will never have null values to worry about; any property that may or may not have a value will be of type Optional<T>, which has properties "IsDefined" (a boolean indicating whether or not it has a value) and "Value" (which is the value itself, so long as "IsDefined" is true).

If you were in an argumentative mood, then you might say that Optional<T> can't save you from nulls in all cases since any code that deals with them could choose not to check "IsDefined" and to just try to access "className.Value" in all cases. This is true, but this faulty style of calling code had to be explicitly written to "work around" the Optional<T> wrapper. If the person who wrote it had sufficiently little interest to try to understand why Optional<T> was used then they may need some help in getting back on to the right path in their programming. This wrapper type acts as a sign post at each point where a null may be encountered, if the sign posts are ignored then that's unfortunate (but the benefit remains that there is a sign post for every potentially-null value whereas, in normal C# code, you need to be wary that nulls may leap out at you at any point, without warning).

This change doesn't affect how you call the constructor if you used the named arguments approach from above, so the following works fine:

new TextInput.Props(
  className: "title",
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

as does:

new TextInput.Props(
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

If you wanted to really deliberately indicate that a TextInput should have no title then you could use any of the following three -

// The explicit way
new TextInput.Props(
  className: Optional<string>.Missing,
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

// The implicit way (there is an implicit cast from T to Optional<T>, which is why passing
// the string "title" in the earlier example works, because the "title" string is implicitly
// cast to an Optional<string> with value "title" - similarly null is implicitly cast to
// an Optional<string> with value null, which is the same as Optional<string>.Missing)
new TextInput.Props(
  className: null,
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

// Using the struct's constructor - the most verbose and least-prefered way. Note that this
// is the only way that a "Missing" value may be specified as a constructor argument's
// default value, as may be seen in the Props constructor above (this is because default
// argument values must be compile time constants, which a new instance of a struct is but
// the static "Missing" property is not. Null can't be used as a constructor argument's
// default value for an Optional as the implicit cast is a runtime operation and so is
// not available at compile time).
new TextInput.Props(
  className: new Optional<string>(),
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

I'm still not happy with this, though. I talked earlier about the ambiguity between null and blank string - for the "Value" property, this is solved since it can never be null now. It's valid for it to be a blank string (if there is no content in the input box) but it's not valid for it to be null (an ArgumentNullException will be raised in the constructor for a null "value"). Problem solved. However, the "ClassName" property can be "Optional<string>.Missing" (which is similar to null) or it can be a value that is a blank string. It would be much better to say that "ClassName" is "Missing" (meaning that it has no value and that the DOM element should have a "class" attribute at all) or that it has a value that is not blank.

One way to try to address this would be with another type -

using System;

namespace BridgeReactTutorial.API
{
  public class NonBlankTrimmedString
  {
    public NonBlankTrimmedString(string value)
    {
      if (string.IsNullOrWhiteSpace(value))
        throw new ArgumentException("Null, blank or whitespace-only value specified");
      Value = value.Trim();
    }

    /// <summary>
    /// This will never be null, blank or have any leading or trailing whitespace
    /// </summary>
    public string Value { get; }

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a string
    /// </summary>
    public static implicit operator string(NonBlankTrimmedString value)
    {
      if (value == null)
        throw new ArgumentNullException("value");
      return value.Value;
    }
  }
}

I said that I wasn't keen on writing out more of this type of "This will never be null.." summary comment if I could avoid it, but the idea with this class it that it will be applicable in multiple places. So I have had to type "This will never be null, blank or have any leading or trailing whitespace" once again but I will take advantage of this one comment over and over again throughout my code.

Now the TextInput.Props class becomes:

public class Props : IAmImmutable
{
  public Props(
    string content,
    bool disabled,
    Action<string> onChange,
    Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
  {
    this.CtorSet(_ => _.Content, content);
    this.CtorSet(_ => _.Disabled, disabled);
    this.CtorSet(_ => _.OnChange, onChange);
    this.CtorSet(_ => _.ClassName, className);
  }
  public Optional<NonBlankTrimmedString> ClassName { get; }
  public bool Disabled { get; }
  public string Content { get; }
  public Action<string> OnChange { get; }
}

If you wanted to instantiate one then you would need to change the calling code slightly - eg.

new TextInput.Props(
  className: new NonBlankTrimmedString("title"),
  value: title,
  disabled: isSaveInProgress,
  onChange: onTitleChange
)

This does make this code a little more verbose. But we have the benefit that the Props class contains more information about what is and isn't acceptable for its property values. Also, making the calling code more explicit like this forces the writer to consider whether an appropriate value will always be passed to it - they should be careful to pass null or "Optional<NonBlankTrimmedString>.Missing" if they don't want to set a class name and to provide a populated, non-blank string if they do want a class name.

At this point, I'm finally satisfied with the TextInput.Props class!

Note: This is probably the most controversial part of my recommended approach - if you're happy to consider making your classes immutable like this, for the reasons I outlined above (which, by the way, can be applied to all classes in your code, not just props types for React components) and you're willing to consider the benefits and trade-offs of building up a more detailed type system (such as using Optional<NonBlankOrTrimmedString> instead of just "string" and only using "string" to mean "non-nullable string") then I think that you'll enjoy the rest of what I've got to say.

I want to extend this ostracising of nulls to the TextInput class itself, though. At the end of Part Two, the component looked like this:

using System;
using Bridge.Html5;
using Bridge.React;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class TextInput : StatelessComponent<TextInput.Props>
  {
    public TextInput(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.Input(new InputAttributes
      {
        Type = InputType.Text,
        ClassName = props.ClassName,
        Disabled = props.Disabled,
        Value = props.Content,
        OnChange = e => props.OnChange(e.CurrentTarget.Value)
      });
    }

    public class Props : IAmImmutable
    {
      public string ClassName;
      public bool Disabled;
      public string Content;
      public Action<string> OnChange;
    }
  }
}

My problem with this is that it's possible to call the constructor with a null "props" value - but, if you do so, then the "Render" method will throw a null reference exception. Unfortunately, it's not possible to check for a null "props" value in the component's constructor due to the way that the Bridge / React bindings work with the React library; the constructor is never actually executed and so a null-check in there would never run. What I suggest is that the Props constructor arguments be repeated in the component's constructor -

using System;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class TextInput : StatelessComponent<TextInput.Props>
  {
    public TextInput(
      string content,
      bool disabled,
      Action<string> onChange,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(content, disabled, onChange, className)) { }

    public override ReactElement Render()
    {
      return DOM.Input(new InputAttributes
      {
        Type = InputType.Text,
        ClassName = props.ClassName.IsDefined ? props.ClassName.Value : null,
        Disabled = props.Disabled,
        Value = props.Content,
        OnChange = e => props.OnChange(e.CurrentTarget.Value)
      });
    }

    public class Props : IAmImmutable
    {
      public Props(
        string content,
        bool disabled,
        Action<string> onChange,
        Optional<NonBlankTrimmedString> className)
      {
        this.CtorSet(_ => _.Content, content);
        this.CtorSet(_ => _.Disabled, disabled);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.ClassName, className);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public bool Disabled { get; }
      public string Content { get; }
      public Action<string> OnChange { get; }
    }
  }
}

Again, this has expanded the amount of code that is required within the component class. But the real effect is magnified by the line-wrapping that I use on my blog post code samples - in Visual Studio, I would likely have the constructor arguments all on one line.

If we can get past the cost of additional code within the component then we get two benefits. The first is that it's no longer possible for the TextInput to ever have a null "props" reference as a Props reference is no longer passed in, but is created in the call to the base constructor by using the individual arguments passed to the TextInput constructor. The second benefit is more marginal, but still nice (especially since it partially offsets the additional code added above) - the way that a new TextInput was declared previously required duplication of the word "TextInput" (with "new TextInput" and "new TextInput.Props") -

new TextInput(new TextInput.Props
{
  ClassName = "title"
  Disabled = props.Disabled,
  Content = props.Content,
  OnChange = props.OnChange
})

With the updated TextInput implementation, this duplication is avoided -

new TextInput(
  className: new NonBlankTrimmedString("title"),
  disabled: props.Disabled,
  content: props.Content,
  onChange: props.OnChange
)

Even without this (admittedly minor) second benefit, I would still be much happier with the new version of TextInput. The additional code (the final version is definitely somewhat longer than the previous version) pays for itself in what it communicates to someone who wishes to consume that component. However, one of the themes that I've been pushing in this series is that components should be dumb and that the real logic of the application should be outside of any UI classes; in the application code that will deal with the complications of the business logic and how to deal with user interactions.. if there is a way to move some of the syntactic noise around component creation away from the complicated library code and into the dumb components, then that seems a sensible trade-off. And that's what has been done here!

There's actually a third benefit to using this "IAmImmutable style" for writing these data types, when it comes to passing events from the simple components all the way up to the top of the component tree, where each "OnChange" (or whatever) adds increasing detail on the way up - but I'll come to that later on, first I want to address a burning question:

If it's so effective to work on the basis that null should not be allowed anywhere in components and their Props, why not use this approach elsewhere in the application?

Trick question! I am convinced that it does make sense to use IAmImmutable for data types throughout the application and to make null arguments and properties unacceptable in all places.

One obvious example is in the "SaveMessage" method in the MessageApi class. Currently, it starts like this:

private RequestId SaveMessage(MessageDetails message, Action optionalSaveCompletedCallback)
{
  if (message == null)
    throw new ArgumentNullException("message");
  if (string.IsNullOrWhiteSpace(message.Title))
    throw new ArgumentException("A title value must be provided");
  if (string.IsNullOrWhiteSpace(message.Content))
    throw new ArgumentException("A content value must be provided");

Not accepting a null MessageDetails instance is good - if someone tried to call this method with a null "message" argument then it should be rejected immediately. However, it feels wrong that it's necessary to then check the "Title" and "Content" properties - should there ever be a case where a MessageDetails instance exists without these values being populated? In this application, the answer is no - the MessageEditor component only allows a new message to be saved if both its Title and Content have values.

This is another opportunity to encode this additional information into the type system. Instead of MessageDetails being implemented like this:

namespace BridgeReactTutorial.ViewModels
{
  public class MessageDetails
  {
    public string Title;
    public string Content;
  }
}

It should be rewritten thusly:

using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.ViewModels
{
  public class MessageDetails : IAmImmutable
  {
    public MessageDetails(NonBlankTrimmedString title, NonBlankTrimmedString content)
    {
      this.CtorSet(_ => _.Title, title);
      this.CtorSet(_ => _.Content, content);
    }
    public NonBlankTrimmedString Title { get; }
    public NonBlankTrimmedString Content { get; }
  }
}

Now, the "SaveMessage" validation is much simpler - all that is required is:

private RequestId SaveMessage(MessageDetails message, Action optionalSaveCompletedCallback)
{
  if (message == null)
    throw new ArgumentNullException("message");

Since a MessageDetails instance may no longer exist with missing Title or Content values, the property validation in "SaveMessage" is unnecessary. This has the benefit that there is less code at the point at which data is retrieved from a MessageDetails instance, which goes some way to offsetting the additional code required in defining the type. The real benefit, though, to removing that code is not just reducing line count but in removing potential duplication (the property validation code may have appeared elsewhere in the application if there were other methods that processed MessageDetails instances) and baking assumptions into the type system, rather than leaving them be implicit. Before, it was probably safe to assume that Title and Content would always have values since the code that would create a MessageDetails instance would always give them values - however, that was only an assumption and you would have had to have read all of the code that created MessageDetails instances to be confident. With this arrangement, you know that a MessageDetails has both Title and Content values at all times, since it's not possible for an instance to be created that doesn't!

When I talk about code being easy to reason about, it's not usually in terms of the dozen or so lines of code that are directly in front of you, it's how the objects and methods that you're dealing with may interact with the rest of the system and what assumptions are being made. Knowing that a MessageDetails instance will always be valid is extremely helpful. Knowing that any code that attempts to create a MessageDetails with invalid data will fail immediately, rather than cause an error later on (when the instance is presumed to be valid but turns out not to be) is extremely helpful. Knowing that a type is immutable and that it won't be changed "behind the scenes" when you pass it off to another method is extremely helpful - when types are mutable and you pass an instance to another method to read, you can't be sure whether the method will only read it or whether it will manipulate it; there's no way to tell from the method signature. Making mutations explicit by making types immutable is another big win for being able to reason about code.

Speaking of dealing with mutation brings me smoothly onto the third benefit of IAmImmutable that I hinted at earlier. Currently, the MessageEditor component in our example app looks like this:

using System;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        !string.IsNullOrWhiteSpace(props.Message.Title.ValidationError) ||
        !string.IsNullOrWhiteSpace(props.Message.Content.ValidationError);

      return DOM.FieldSet(new FieldSetAttributes { ClassName = props.ClassName },
        DOM.Legend(null, props.Message.Caption),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "title",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Title.Text,
          OnChange = newTitle => props.OnChange(new MessageEditState
          {
            Title = new TextEditState { Text = newTitle },
            Content = props.Message.Content
          }),
          ValidationMessage = props.Message.Title.ValidationError
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "content",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Content.Text,
          OnChange = newContent => props.OnChange(new MessageEditState
          {
            Title = props.Message.Title,
            Content = new TextEditState { Text = newContent },
          }),
          ValidationMessage = props.Message.Content.ValidationError
        }),
        DOM.Button(
        new ButtonAttributes
        {
          Disabled = formIsInvalid || props.Message.IsSaveInProgress,
          OnClick = e => props.OnSave()
        },
        "Save"
        )
      );
    }

    public class Props
    {
      public string ClassName;
      public MessageEditState Message;
      public Action<MessageEditState> OnChange;
      public Action OnSave;
    }
  }
}

The first thing I'm going to do is change the Props type and the component's constructor in the same way as I did for the TextInput -

using System;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(
      MessageEditState message,
      Action<MessageEditState> onChange,
      Action onSave,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, message, onChange, onSave)) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        !string.IsNullOrWhiteSpace(props.Message.Title.ValidationError) ||
        !string.IsNullOrWhiteSpace(props.Message.Content.ValidationError);

      return DOM.FieldSet(
        new FieldSetAttributes {
          ClassName = props.ClassName.IsDefined ? props.ClassName.Value : null
        },
        DOM.Legend(null, props.Message.Caption),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "title",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Title.Text,
          OnChange = newTitle => props.OnChange(new MessageEditState
          {
            Title = new TextEditState { Text = newTitle },
            Content = props.Message.Content
          }),
          ValidationMessage = props.Message.Title.ValidationError
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "content",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Content.Text,
          OnChange = newContent => props.OnChange(new MessageEditState
          {
            Title = props.Message.Title,
            Content = new TextEditState { Text = newContent },
          }),
          ValidationMessage = props.Message.Content.ValidationError
        }),
        DOM.Button(
        new ButtonAttributes
        {
          Disabled = formIsInvalid || props.Message.IsSaveInProgress,
          OnClick = e => props.OnSave()
        },
        "Save"
        )
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        MessageEditState message,
        Action<MessageEditState> onChange,
        Action onSave)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Message, message);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.OnSave, onSave);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public MessageEditState Message { get; }
      public Action<MessageEditState> OnChange { get; }
      public Action OnSave { get; }
    }
  }
}

This means that the MessageEditor instantiation code changes slightly from:

new MessageEditor(new MessageEditor.Props
{
  ClassName = "message",
  Message = state.Message,
  OnChange = newState => props.Dispatcher.Dispatch(
    UserEditRequested.For(newState)
  ),
  OnSave = () => props.Dispatcher.Dispatch(
    SaveRequested.For(
      new MessageDetails(
        new NonBlankTrimmedString(state.Message.Title.Text),
        new NonBlankTrimmedString(state.Message.Content.Text)
      )
    )
  )
}),

to:

new MessageEditor(
  className: new NonBlankTrimmedString("message"),
  message:  state.Message,
  onChange: newState => props.Dispatcher.Dispatch(
    UserEditRequested.For(newState)
  ),
  onSave: () => props.Dispatcher.Dispatch(
    SaveRequested.For(
      new MessageDetails(
        new NonBlankTrimmedString(state.Message.Title.Text),
        new NonBlankTrimmedString(state.Message.Content.Text)
      )
    )
  )
),

There are several steps that need following now until I can reveal my point, so bear with me. I'm going to change the MessageEditState data type, in the same way as I did the MessageDetails - from:

namespace BridgeReactTutorial.ViewModels
{
  public class MessageEditState
  {
    public string Caption;
    public TextEditState Title;
    public TextEditState Content;
    public bool IsSaveInProgress;
  }
}

to:

using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.ViewModels
{
  public class MessageEditState : IAmImmutable
  {
    public MessageEditState(
      NonBlankTrimmedString caption,
      TextEditState title,
      TextEditState content,
      bool isSaveInProgress)
    {
      this.CtorSet(_ => _.Caption, caption);
      this.CtorSet(_ => _.Title, title);
      this.CtorSet(_ => _.Content, content);
      this.CtorSet(_ => _.IsSaveInProgress, isSaveInProgress);
    }
    public NonBlankTrimmedString Caption { get; }
    public TextEditState Title { get; }
    public TextEditState Content { get; }
    public bool IsSaveInProgress { get; }
  }
}

And do the same with TextEditState, from -

namespace BridgeReactTutorial.ViewModels
{
    public class TextEditState
    {
        public string Text;
        public string ValidationError;
    }
}

to:

using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.ViewModels
{
  public class TextEditState : IAmImmutable
  {
    public TextEditState(
      string text,
      Optional<NonBlankTrimmedString> validationError = new Optional<NonBlankTrimmedString>())
    {
      this.CtorSet(_ => _.Text, text);
      this.CtorSet(_ => _.ValidationError, validationError);
    }
    public string Text { get; }
    public Optional<NonBlankTrimmedString> ValidationError { get; }
  }
}

I'm going to change the ValidatedTextInput to

using System;
using Bridge.React;
using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class ValidatedTextInput : StatelessComponent<ValidatedTextInput.Props>
  {
    public ValidatedTextInput(
      bool disabled,
      string content,
      Action<string> onChange,
      Optional<NonBlankTrimmedString> validationMessage,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, disabled, content, onChange, validationMessage)) { }

    public override ReactElement Render()
    {
      var className = props.ClassName;
      if (props.ValidationMessage.IsDefined)
        className = className.Add(" ", new NonBlankTrimmedString("invalid"));
      return DOM.Span(new Attributes { ClassName = className.ToStringIfDefined() },
        new TextInput(
          className: props.ClassName,
          disabled: props.Disabled,
          content: props.Content,
          onChange: props.OnChange
        ),
        props.ValidationMessage.IsDefined
        ? DOM.Span(
          new Attributes { ClassName = "validation-message" },
          props.ValidationMessage.ToStringIfDefined()
        )
        : null
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        bool disabled,
        string content,
        Action<string> onChange,
        Optional<NonBlankTrimmedString> validationMessage)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Disabled, disabled);
        this.CtorSet(_ => _.Content, content);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.ValidationMessage, validationMessage);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public bool Disabled { get; }
      public string Content { get; }
      public Action<string> OnChange { get; }
      public Optional<NonBlankTrimmedString> ValidationMessage { get; }
    }
  }
}

.. which requires a new class be added to the "API" folder with some extension methods to make dealing with Optional<NonBlankTrimmedString> a little nicer -

using System;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.API
{
  public static class OptionalNonBlankTrimmedStringExtensions
  {
    /// <summary>
    /// If the Optional NonBlankTrimmedString has a value then it will be unwrapped directly
    /// into a string - if not, the null will be returned (this is one of the few places
    /// where null will be an acceptable value in the app and it should be only used when
    /// integrating with code that expects nulls - such as when setting attributes via
    /// React html element factories)
    /// </summary>
    public static string ToStringIfDefined(this Optional<NonBlankTrimmedString> source)
    {
      return source.IsDefined ? source.Value : null;
    }

    /// <summary>
    /// This will join two Optional NonBlankTrimmedString with a specified delimiter if
    /// they both have values. If only one of them has a value then this will be returned
    /// unaltered. If neither of them have a value then a Missing value will be returned.
    /// </summary>
    public static Optional<NonBlankTrimmedString> Add(
      this Optional<NonBlankTrimmedString> source,
      string delimiter,
      Optional<NonBlankTrimmedString> other)
    {
      if (delimiter == null)
        throw new ArgumentNullException("delimiter");

      if (!source.IsDefined && !other.IsDefined)
        return Optional<NonBlankTrimmedString>.Missing;
      else if (!source.IsDefined)
        return other;
      else if (!other.IsDefined)
        return source;

      return new NonBlankTrimmedString(source.Value.Value + delimiter + other.Value.Value);
    }
  }
}

and a further implicit operator adding to the NonBlankTrimmedString -

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a ReactElement-or-string, such as for the children array of the React
    /// DOM component factories
    /// </summary>
    public static implicit operator Union<ReactElement, string>(NonBlankTrimmedString value)
    {
        if (value == null)
            throw new ArgumentNullException("value");
        return value.Value;
    }

Ok, now I'm finally able to demonstrate this mysterious third benefit. The "OnChange" lambdas which were provided as ValidatedTextInput.Props values by the MessageEditor's "Render" method were previously specified like this:

OnChange = newTitle => props.OnChange(new MessageEditState
{
  Title = new TextEditState { Text = newTitle },
  Content = props.Message.Content
})

OnChange = newContent => props.OnChange(new MessageEditState
{
  Title = props.Message.Title,
  Content = new TextEditState { Text = newContent },
})

Within each "OnChange", we want to create a new MessageEditState instance with one of the properties changed. However, it get arduous having to repeat all of the property names each time that you want to change a single property - here it's not that bad because there are only two properties ("Title" and "Content"), but on classes with more properties this is annoying and, worse, error-prone.

Now that MessageEditState implements IAmImmutable, we can take advantage of another extension method available; "With". This takes an argument that specifies the property to change and it takes an argument for the new property value. This means that

OnChange = newTitle => props.OnChange(new MessageEditState
{
  Title = new TextEditState { Text = newTitle },
  Content = props.Message.Content
})

is replaced with

OnChange = newTitle => props.OnChange(
   props.Message.With(_ => _.Title, new TextEditState(newTitle))
)

and

OnChange = newContent => props.OnChange(new MessageEditState
{
  Title = props.Message.Title,
  Content = new TextEditState { Text = newContent }
})

is replaced with

OnChange = newContent => props.OnChange(
  props.Message.With(_ => _.Content, new TextEditState(newContent))
)

(Again, I'm only wrapping these lines for the sake of the formatting on my blog - if I was writing this code in Visual Studio then I would make those a single line each).

The "With" function takes an instance of an IAmImmutable-implementing class, clones it but changes the specified property value - unless the new value is the same as the old value, in which case it returns the original instance unaltered.

All of these changes combined mean that the MessageEditor component now becomes:

using System;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(
      MessageEditState message,
      Action<MessageEditState> onChange,
      Action onSave,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, message, onChange, onSave)) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        props.Message.Title.ValidationError.IsDefined ||
        props.Message.Content.ValidationError.IsDefined;

      return DOM.FieldSet(
        new FieldSetAttributes { ClassName = props.ClassName.ToStringIfDefined() },
        DOM.Legend(null, props.Message.Caption),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(
          className: new NonBlankTrimmedString("title"),
          disabled: props.Message.IsSaveInProgress,
          content: props.Message.Title.Text,
          onChange: newTitle => props.OnChange(
            props.Message.With(_ => _.Title, new TextEditState(newTitle))
          ),
          validationMessage: props.Message.Title.ValidationError
        ),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(
          className: new NonBlankTrimmedString("content"),
          disabled: props.Message.IsSaveInProgress,
          content: props.Message.Content.Text,
          onChange: newContent => props.OnChange(
            props.Message.With(_ => _.Content, new TextEditState(newContent))
          ),
          validationMessage: props.Message.Content.ValidationError
        ),
        DOM.Button(
        new ButtonAttributes
        {
          Disabled = formIsInvalid || props.Message.IsSaveInProgress,
          OnClick = e => props.OnSave()
        },
        "Save"
        )
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        MessageEditState message,
        Action<MessageEditState> onChange,
        Action onSave)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Message, message);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.OnSave, onSave);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public MessageEditState Message { get; }
      public Action<MessageEditState> OnChange { get; }
      public Action OnSave { get; }
    }
  }
}

One more example

Before moving on, I want to apply these changes to one more component to really drive the point home.

This is the MessageHistory component as it currently stands:

using System;
using System.Collections.Generic;
using System.Linq;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageHistory : StatelessComponent<MessageHistory.Props>
  {
    public MessageHistory(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var className = props.ClassName;
      if (!props.Messages.Any())
        className = (className + " zero-messages").Trim();

      // Any time a set of child components is dynamically-created (meaning that the
      // numbers of items may vary from one render to another), each must have a unique
      // "Key" property set (this may be a int or a string). Here, this is simple as
      // each message tuple is a unique ID and the contents of that message.
      var messageElements = props.Messages
        .Select(idAndMessage => DOM.Div(new Attributes { Key = idAndMessage.Item1 },
        DOM.Span(new Attributes { ClassName = "title" }, idAndMessage.Item2.Title),
        DOM.Span(new Attributes { ClassName = "content" }, idAndMessage.Item2.Content)
      ));

      // When child components are specified (as they are through the second argument of
      // DOM.Div), the argument is of type Union<ReactElement, string>[] (meaning that each
      // element may be another component or it may be a simple text value)
      // - The React bindings have an extension method that transforms an IEnumerable set
      //   of components (such as "messageElements") into an Union<ReactElement, string>[]
      return DOM.FieldSet(new FieldSetAttributes { ClassName = className },
        DOM.Legend(null, "Message History"),
        DOM.Div(null, messageElements)
      );
    }

    public class Props
    {
      public string ClassName;
      public IEnumerable<Tuple<int, MessageDetails>> Messages;
    }
  }
}

Despite this appearing very simple at first glance, there are various implicit assumptions that you should be aware of. Firstly, it is assumed that "props" will never be null ("Render" will throw an exception if this is not the case). It is also assumed that "props.ClassName" may be null (and, technically, it may also be a blank string, though this is not desirable) while "props.Messages" should not null. Nor should "props.Messages" contain any tuples with a null MessageDetails instance. But these assumptions are neither documented nor enforced.

By this point, we've seen several examples of how to prevent "props" being null (ie. require that the props constructor arguments be passed as the component's constructor arguments) and we've seen how to better represent Props to allow "ClassName" to be optional but for "Messages" to not be ("ClassName" should be an Optional<NonBlankTrimmedString>). But there are two further tricks we can use for the MessageHistory.Props.

Firstly, IEnumerable is too loose for my liking - technically, there are no guarantees that an IEnumerable will report the same information if enumerated multiple times and there are definitely no guarantees that it won't contain any null references. I want consistency and I want a life free from null. The ProductiveRage.Immutable library contains another handy class for this sort of thing; NonNullList<T>. This is essentially an ordered list of items of type "T" that is immutable and that will never contain any null values. If you want a set of items that may or may not have values of type "T" then you need the list type to be NonNullList<Optional<T>>.

The second tweak that I want to make is to replace the Tuple<int, MessageDetails> - in part, again, because there is no guarantee that the second item in the pair will not be null but also because I don't like the "Item1" and "Item2" property names. I think it's just one more thing to mentally translate ("Oh yes, Item1 means Key and Item2 means Message"). So I'm going to extend the type system again.

When considering a simple API, the common actions are "Create", "Read", "Update", "Delete". When creating a new item (like when we save a new message in our example application), we don't have a unique key for the new message - that will be generated by the persistence layer as part of the save process. When we read values (to display existing messages in the MessageHistory, for example), we will have access to unique keys - the persistence layer will be reading data from wherever the data is stored and it will be able to draw the keys out along with the data. When updating an existing record, we should know what its key is, since we will have performed a read action in order to get the currently-persisted state for the record. Similarly, when requesting a delete, we will have the key from a previous read action, in order to know what record to remove.

I've seen object models before which try to have a single data type to use in all of the Create, Read and Update cases. This would be like our MessageDetails having a "Key", "Title" and "Content". However, sometimes the "Key" would be null because it would be unknown (when generating a brand new MessageDetails instance to pass to "SaveMessage", for example). I don't like this. The sometimes-Key-is-null-and-sometimes-it-isn't is an unnecessary complication and it means that there are places where we require a Key but can't guarantee (through the type system) that the reference that we have will have a non-null Key value. I think it's much better to have two data types; one for a record that has been persisted at some point (and thus has a non-null Key) and another type for a record that may or may not have been persisted. Currently, our MessageDetails class (which has only "Title" and "Content" properties) represents a message that may or may not have been persisted - when a new one is passed to "SaveMessage" when the user attempts to save a new message then we know that it hasn't been persisted yet, but it's not difficult to imagine that there could be other code that we add to the application in the future that wants to deal with some message data, but that doesn't care whether it's been persisted or not yet; it only wants access to its "Title" and / or "Content" values, it doesn't need the "Key" for anything.

So, instead of the MessageHistory using the generic Tuple class to represent a MessageDetails-plus-persisted-Key, I'm going to introduce something new. Create a new file under the "API" folder, "Saved.cs" -

using ProductiveRage.Immutable;

namespace BridgeReactTutorial.API
{
  public class Saved<TKey, TValue> : IAmImmutable
  {
    public Saved(TKey key, TValue value)
    {
      this.CtorSet(_ => _.Key, key);
      this.CtorSet(_ => _.Value, value);
    }
    public TKey Key { get; }
    public TValue Value { get; }
  }

  public static class Saved
  {
    /// <summary>
    /// This generic method makes code that creates generic Saved instances more succinct
    /// by relying upon type inference (based upon the key and value argument types), so
    /// that the calling code does not have to explicitly declare TKey and TValue
    /// </summary>
    public static Saved<TKey, TValue> For<TKey, TValue>(TKey key, TValue value)
    {
      return new Saved<TKey, TValue>(key, value);
    }
  }
}

The Saved class makes differentiating between record-that-has-a-persistence-id and record-that-may-or-may-not-have-a-persistence-id simple. If the message has been persisted, then it may be represented as a Saved<int, MessageDetails>. If it's just the message data, with no persisted-or-not-persisted state associated with it then it will be simply a MessageDetails.

I'm still not happy, though. I think that Saved<int, MessageDetails> could still be more descriptive. This value represents a message with a unique persistence key for that message. Even if the underlying data store is a database which uses an integer column (in our example app, it's a simple in-browser-memory store, but a database on a server is likely much more common) that doesn't mean that we have to use such a vague term as "an integer" in our application's object model. I recommend strongly-typed ID representations. We need to add a new file "MessageId.cs" to the "API" folder:

namespace BridgeReactTutorial.API
{
  public struct MessageId
  {
    public int Value { get; private set; }

    public static explicit operator MessageId(int value)
    {
      return new MessageId { Value = value };
    }

    public static implicit operator int(MessageId id)
    {
      return id.Value;
    }
  }
}

This is the final step in the move away from IEnumerable<Tuple<int, MessageDetails>>, we will now represent this data with the type NonNullList<Saved<MessageId, MessageDetails>>. This list will never contain any null "Saved" instances and a "Saved" instance will never contain a null message. This list of messages will never vary, which is another way that React's "consider props to be immutable" guidelines is described and enforced in the type system.

Not only do I believe that having strongly-typed IDs makes the code clearer in cases like this but it can also avoid silly mistakes that have a nasty tendency to crop up from time to time - if you're writing code and having a bad day, then it's easy to accidentally pass the wrong ID around. For example, if I have a function:

void RecordMessageAsHavingBeenReadBy(int messageId, int userId)

then it's possible in the calling code to mix up the IDs if you're having a bad day (this isn't too contrived an example, I have done something like this in the past!) - eg.

RecordMessageAsHavingBeenReadBy(user.Id, message.id); // Whoops!

If the IDs were strongly-typed, meaning that the method signature would be..

void RecordMessageAsHavingBeenReadBy(MessageId messageId, UserId userId)

.. then that mishap would result in a compile error, rather than runtime confusion that may not get noticed immediately.

(Note: These changes to how messages are represented will require changes to the MessageApi, which I'll cover shortly - nothing very complicated, though).

These changes lead the MessageHistory component's code to now look like this:

using System.Linq;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class MessageHistory : StatelessComponent<MessageHistory.Props>
  {
    public MessageHistory(
      NonNullList<Saved<MessageId, MessageDetails>> messages,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, messages)) { }

    public override ReactElement Render()
    {
      var className = props.ClassName;
      if (!props.Messages.Any())
        className = className.Add(" ", new NonBlankTrimmedString("zero-messages"));

      // Any time a set of child components is dynamically-created (meaning that the
      // numbers of items may vary from one render to another), each must have a unique
      // "Key" property set (this may be a int or a string)
      var messageElements = props.Messages
        .Select(savedMessage => DOM.Div(new Attributes { Key = (int)savedMessage.Key },
        DOM.Span(new Attributes { ClassName = "title" }, savedMessage.Value.Title),
        DOM.Span(new Attributes { ClassName = "content" }, savedMessage.Value.Content)
        ));

      // When child components are specified (as they are through the second argument of
      // DOM.Div), the argument is of type Union<ReactElement, string>[] (meaning that each
      // element may be another component or it may be a simple text value)
      // - The React bindings have an extension method that transforms an IEnumerable set
      //   of components (such as "messageElements") into an Union<ReactElement, string>[]
      return DOM.FieldSet(
        new FieldSetAttributes { ClassName = className.ToStringIfDefined() },
        DOM.Legend(null, "Message History"),
        DOM.Div(null, messageElements)
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        NonNullList<Saved<MessageId, MessageDetails>> messages)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Messages, messages);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public NonNullList<Saved<MessageId, MessageDetails>> Messages { get; }
    }
  }
}

All of those implicit assumptions are now explicitly described in the type system. This makes me feel much better.

So, EVERYWHERE?

I introduced the use of IAmImmutable in terms of a component's Props class. But I subsequently used it to tighten up the MessageDetails class and then again when the Saved class was added.

One option in incorporating IAmImmutable and this no-value-or-property-may-be-null behaviour into applications would be to say that any class that implements IAmImmutable will not allow null anywhere. As I've already hinted, I strongly suggest going further than that, however, and writing all code like this. Frankly, I can see no good reason why any public data type should be mutable. I can imagine that, in some special cases, it may be desirable to have some private mutable data structures for convenience, or maybe performance (in some very specialised cases) but where the data is shared with other classes, data types being immutable makes the code much easier to reason about. Transformations are explicit and do not occur "in place" for any references. Meaning that a reference that describes some data when a function starts will always describe the same data when the function ends.

It's actually worth remembering that JavaScript in the browser is single-threaded. A lot of the time that people talk about the benefits of immutability, they talk about the safety of being able to share references between multiple threads and not having to worry about corruption because one thread can't manipulate data in a way that another thread doesn't expect, with unfortunate (and often non-deterministic) results. Here, we are not concerned about multi-threading, I recommend the use of immutable structures solely because they make the code that accesses them and passes them around easier to reason about.

The largest downside in my eyes, as may have struck you after reading all of the above, is that changing code that doesn't use IAmImmutable into code that does use it requires changes not only to that particular class but, in many cases, to code that accesses or initialises that class and then to code that accesses or initialises that code (the changes to the MessageEditor and MessageHistory components required changes to the MessageDetails and MessageEditState classes and still require more changes to the AppContainer, the MessageWriterStore and the MessageApi). It's much better to bake this in from the start. The big benefit is that, if you do so, you'll rarely have to worry about "could this value be null"* and "could this data be changed if I pass it into another function".

* (There will still be some places where you have to be alert about potential nulls, but these should largely arise from interacting with other libraries - the "ToStringIfDefined" extension method we saw earlier is an example of a place where nulls may be returned, but it is clearly documented as such and the return value is only intended to be passed to a React element factory method).

Filling in more gaps

If you've been following along and creating your own project with the code in this series, you will be all too aware that it doesn't build at the moment. Let's go through and fix everything up. Much of the required alterations will be similar to what is presented above, but there are a few other tips and tricks to consider along the way.

Let's start with the AppContainer. Last we saw it, it looked like this:

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;
using BridgeReactTutorial.Stores;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, AppContainer.State>
  {
    public AppContainer(AppContainer.Props props) : base(props) { }

    protected override void ComponentDidMount()
    {
      props.Store.Change += StoreChanged;
    }
    protected override void ComponentWillUnmount()
    {
      props.Store.Change -= StoreChanged;
    }
    private void StoreChanged()
    {
      SetState(new State
      {
        Message = props.Store.Message,
        MessageHistory = props.Store.MessageHistory
      });
    }

    public override ReactElement Render()
    {
      if (state == null)
        return null;

      return DOM.Div(null,
        new MessageEditor(
          className: new NonBlankTrimmedString("message"),
          message:  state.Message,
          onChange: newState => props.Dispatcher.Dispatch(
            UserEditRequested.For(newState)
          ),
          onSave: () => props.Dispatcher.Dispatch(
            SaveRequested.For(
              new MessageDetails(
                new NonBlankTrimmedString(state.Message.Title.Text),
                new NonBlankTrimmedString(state.Message.Content.Text)
              )
            )
          )
        ),
        new MessageHistory(new MessageHistory.Props
        {
          ClassName = "history",
          Messages = state.MessageHistory
        })
      );
    }

    public class Props
    {
      public AppDispatcher Dispatcher;
      public MessageWriterStore Store;
    }

    public class State
    {
      public MessageEditState Message;
      public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;
    }
  }
}

It's nice and simple since we moved nearly all of the logic that it contained in Part One into the MessageWriterStore in Part Two.

The obvious thing to do, based on what I've been talking about today, is to change its Props and State classes to implement IAmImmutable.

After that, there is one difference between this component and the other components we've already looked at - this is stateful and they were state-less. That means that they only had "props" to think about, while the AppContainer has both "props" and "state". As with the stateless components, it is presumed that the "props" reference may never be null. This can be enforced by using the same trick as we did for the others - mirror the Props constructor arguments in the AppContainer's constructor arguments and generate a Props instance from them. However, the "state" reference may be null some times, as can be seen at the very start of the "Render" method. This means that the "state" type should be Optional<State>, rather than just State.

These changes result in this:

using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.Stores;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, Optional<AppContainer.State>>
  {
    public AppContainer(AppDispatcher dispatcher, MessageWriterStore store)
      : base(new Props(dispatcher, store)) { }

    protected override void ComponentDidMount()
    {
      props.Store.Change += StoreChanged;
    }
    protected override void ComponentWillUnmount()
    {
      props.Store.Change -= StoreChanged;
    }
    private void StoreChanged()
    {
      SetState(new State(
        message: props.Store.Message,
        messageHistory: props.Store.MessageHistory
      ));
    }

    public override ReactElement Render()
    {
      if (!state.IsDefined)
        return null;

      return DOM.Div(null,
        new MessageEditor(
          className: new NonBlankTrimmedString("message"),
          message:  state.Value.Message,
          onChange: newState => props.Dispatcher.Dispatch(
            UserEditRequested.For(newState)
          ),
          onSave: () => props.Dispatcher.Dispatch(
            SaveRequested.For(
              new MessageDetails(
                new NonBlankTrimmedString(state.Value.Message.Title.Text),
                new NonBlankTrimmedString(state.Value.Message.Content.Text)
              )
            )
          )
        ),
        new MessageHistory(
          className: new NonBlankTrimmedString("history"),
          messages: state.Value.MessageHistory
        )
      );
    }

    public class Props : IAmImmutable
    {
      public Props(AppDispatcher dispatcher, MessageWriterStore store)
      {
        this.CtorSet(_ => _.Dispatcher, dispatcher);
        this.CtorSet(_ => _.Store, store);
      }
      public AppDispatcher Dispatcher { get; }
      public MessageWriterStore Store { get; }
    }

    public class State : IAmImmutable
    {
      public State(
        MessageEditState message,
        NonNullList<Saved<MessageId, MessageDetails>> messageHistory)
      {
        this.CtorSet(_ => _.Message, message);
        this.CtorSet(_ => _.MessageHistory, messageHistory);
      }
      public MessageEditState Message { get; }
      public NonNullList<Saved<MessageId, MessageDetails>> MessageHistory { get; }
    }
  }
}

That transformation should have felt quite run-of-the-mill and predictable by this point - seen one component-tightening-up, seen them all. Let's move on to the MessageWriterStore. This is what deals with the events from the application, both from user-initiated events from DOM elements and from new-messages-data-available events from the MessageApi.

At the bare minimum, it will need some changes since it was written when the MessageEditState type was mutable and so the "ValidateMessage" method was able to mutate it (such as setting or clearing validation warning messages) in-place. I've moved away from that so that mutations are always explicit - there will no longer be a method that may or may not mutate a reference, if a method needs to set values on something then it will take the initial reference as an input and return a new one as its return value. But there are more of those sneaky "implicit assumptions" tucked away in the store that we should address. In the last post, we left it implemented like this:

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Stores
{
  public class MessageWriterStore
  {
    private RequestId _saveActionRequestId, _lastDataUpdatedRequestId;
    public MessageWriterStore(IReadAndWriteMessages messageApi, AppDispatcher dispatcher)
    {
      if (messageApi == null)
        throw new ArgumentNullException("messageApi");
      if (dispatcher == null)
        throw new ArgumentNullException("dispatcher");

      Message = GetInitialMessageEditState();
      MessageHistory = new Tuple<int, MessageDetails>[0];

      dispatcher.Receive(a => a
        .If<StoreInitialised>(
          condition: action => (action.Store == this),
          work: action => { }
        )
        .Else<MessageEditStateChanged>(action =>
        {
          Message = action.NewState;
          ValidateMessage(Message);
        })
        .Else<MessageSaveRequested>(action =>
        {
          _saveActionRequestId = messageApi.SaveMessage(action.Message);
          Message.IsSaveInProgress = true;
        })
        .Else<MessageSaveSucceeded>(
          condition: action => (action.RequestId == _saveActionRequestId),
          work: action =>
          {
            _saveActionRequestId = null;
            Message = GetInitialMessageEditState();
            _lastDataUpdatedRequestId = messageApi.GetMessages();
          }
        )
        .Else<MessageHistoryUpdated>(
          condition: action =>
            action.RequestId.IsEqualToOrComesAfter(_lastDataUpdatedRequestId),
          work: action =>
          {
            _lastDataUpdatedRequestId = action.RequestId;
            MessageHistory = action.Messages;
          }
        )
        .IfAnyMatched(OnChange);
      );
    }

    public event Action Change;
    public MessageEditState Message;
    public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;

    private MessageEditState GetInitialMessageEditState()
    {
      // Note: By using the ValidateMessage here, we don't need to duplicate the "Untitled"
      // string that should be used for the Caption value when the UI is first rendered
      // or when the user has entered some Title content but then deleted it again.
      // Similarly, we avoid having to repeat the validation messages that should be
      // displayed when the form is empty, since they will be set by ValidateMessage.
      var blankMessage = new MessageEditState
      {
        Caption = "",
        Title = new TextEditState { Text = "" },
        Content = new TextEditState { Text = "" },
        IsSaveInProgress = false
      };
      ValidateMessage(blankMessage);
      return blankMessage;
    }

    private void ValidateMessage(MessageEditState message)
    {
      if (message == null)
        throw new ArgumentNullException("message");

      message.Caption = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Untitled"
        : message.Title.Text.Trim();
      message.Title.ValidationError = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Must enter a title"
        : null;
      message.Content.ValidationError = string.IsNullOrWhiteSpace(message.Content.Text)
        ? "Must enter message content"
        : null;
    }

    private void OnChange()
    {
      if (Change != null)
        Change();
    }
  }
}

Three things jump out at me here. Firstly, the "_saveActionRequestId" and "_lastDataUpdatedRequestId" references may not always be populated. If there is no save action in progress that we're waiting to complete, for example, then "_saveActionRequestId" won't have a value. Let's explicitly describe this in the type system by changing the type of these two values from RequestId to Optional<RequestId> (even though these values aren't part of a public API of the store class, there's still a benefit to indicating what may and may not have a value, for the sake of code clarity).

The second thing is that the "Message" and "MessageHistory" properties are only intended to be written to internally. They are available for reading by other classes (like the AppContainer component), but not for updating by other classes. It makes sense to change these from being public fields to being properties with public getters and private setters. This wasn't done originally because I wanted to start from the simplest possible implementations and only stray from that when there was a clear benefit. Today, we're dealing with the clear benefit of increased code clarity through the reduction of implicit assumptions. Moving to private-setter properties allows the compiler to enforce what was only presumed to be true before (instead of working on the assumption that no-one would try to update these references, now we can sleep safe that no-one other than the MessageWriteStore itself can change the references).

The third thing is that "Change" is an event and so may be null if no-one has subscribed to it. That's just the way that events work in C#. We could either come up with a new way to represent events or we could accept that a null check is required (and that we can't use an Optional type to represent it). I think that the pragmatic thing to do is to just accept it - this is basically how events have worked in C# from day one and I don't think that there would be any improvement to code clarity by trying to shy away from this accepted practice.

What is really going to be the most interesting part in updating the MessageWriterStore is, I think, how we change the validation / MessageEditState-mutating code -

private void ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  message.Caption = string.IsNullOrWhiteSpace(message.Title.Text)
    ? "Untitled"
    : message.Title.Text.Trim();
  message.Title.ValidationError = string.IsNullOrWhiteSpace(message.Title.Text)
    ? "Must enter a title"
    : null;
  message.Content.ValidationError = string.IsNullOrWhiteSpace(message.Content.Text)
    ? "Must enter message content"
    : null;
}

Probably the absolute simplest thing that we could do would be to rewrite it like this:

private MessageEditState ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  if (string.IsNullOrWhiteSpace(message.Title.Text))
    message = message.With(_ => _.Caption, new NonBlankTrimmedString("Untitled"));
  else
    message = message.With(_ => _.Caption, new NonBlankTrimmedString(message.Title.Text));

  if (string.IsNullOrWhiteSpace(message.Title.Text))
    message = message.With(_ => _.Title, SetValidationMessage(message.Title, new NonBlankTrimmedString("Must enter a title")));
  else
    message = message.With(_ => _.Title, SetValidationMessage(message.Title, null));

  if (string.IsNullOrWhiteSpace(message.Content.Text))
    message = message.With(_ => _.Content, SetValidationMessage(message.Content, new NonBlankTrimmedString("Must enter message content")));
  else
    message = message.With(_ => _.Content, SetValidationMessage(message.Content, null));

  return message;
}

private TextEditState SetValidationMessage(
  TextEditState textEditState,
  Optional<NonBlankTrimmedString> message)
{
  if (textEditState == null)
    throw new ArgumentNullException("textEditState");

  return textEditState.With(_ => _.ValidationError, message);
}

That is.. more verbose, I think would be a polite way to describe it. I would normally have wrapped some of the lines in order to fit the horizontal scrolling budget I allow on code samples on my blog but I wanted to give this arrangement the best change at looking succint that it could. And it's still not looking very good.

What's much worse, though, is that I don't think that this code is very easy to read. I think that there's quite a lot of noise that masks the actual intent. It's not complicated, by a long shot, but I think that the actual logic that it's trying to apply is drowning a little bit in all the code that's required. The verbosity itself, is not the biggest problem for me - I will take code that is slightly longer if it's clearer (I'm not just talking about descriptive variable and method names and I'm don't mean avoiding compact "clever" code, I mean like the changes from mutable classes to IAmImmutable implementations; they are more verbose but they are much more expressive).

One alternative would be:

private MessageEditState ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  var caption = string.IsNullOrWhiteSpace(message.Title.Text)
    ? new NonBlankTrimmedString("Untitled")
    : new NonBlankTrimmedString(message.Title.Text);
  var titleEditState = string.IsNullOrWhiteSpace(message.Title.Text)
    ? SetValidationMessage(message.Title, new NonBlankTrimmedString("Must enter a title"))
    : null;
  var contentEditState = string.IsNullOrWhiteSpace(message.Content.Text)
    ? SetValidationMessage(message.Content, new NonBlankTrimmedString("Must enter message content"))
    : null;

  return message
    .With(_ => _.Caption, caption)
    .With(_ => _.Title, titleEditState)
    .With(_ => _.Content, contentEditState);
}

This is much improved. The code looks cleaner at a glance and, crucially, it's much clearer in its intent.

However.. the way that we've reduced the syntactic noise is by separating the "what should the new values be" from the "set these new values". This isn't too bad with only three properties, but if the object being validated was more complex then the new-value-determining code would drift further from the new-value-setting code, which would be a pity since they are intrinsically linked concepts (and it would be nice - meaning that the code should be easier to understand at a glance - if the two types of code were linked again for each property, with each new-value-determiner being present alongside the new-value-setter).

Instead of splitting the code up for clarity, we can try to make it clearer by using abstractions.

Let's start by introducing a method to abstract the setting-or-removing of validation messages from TextEditState instances -

private TextEditState Validate(
  TextEditState textEditState,
  Predicate<TextEditState> validIf,
  NonBlankTrimmedString messageIfInvalid)
{
  if (textEditState == null)
    throw new ArgumentNullException("textEditState");
  if (validIf == null)
    throw new ArgumentNullException("validIf");
  if (messageIfInvalid == null)
    throw new ArgumentNullException("messageIfInvalid");

  return textEditState.With(_ => _.ValidationError, validIf(textEditState)
    ? null
    : messageIfInvalid);
}

This will take a TextEditState, a rule that determines whether or not its "Text" value should be considered valid and a message to set if the value is not valid (if it is valid then the message will be cleared).

This would allow us to set (or remove) the validation message on the "Title" property with code such as:

message = message.With(
  _ => _.Title,
  Validate(
    message.Title,
    textEditState => string.IsNullOrWhiteSpace(textEditState.Text),
    new NonBlankTrimmedString("Must enter a title")
  )
);

Since the validation logic for both "Title" and "Content" is the same and "textEditState => string.IsNullOrWhiteSpace(textEditState.Text)" is quite long and going to be responsible for a lot of the "syntactic noise" that I want to avoid, this could also be abstracted by defining another method -

private bool MustHaveValue(TextEditState textEditState)
{
  if (textEditState == null)
    throw new ArgumentNullException("textEditState");

  return !string.IsNullOrWhiteSpace(textEditState.Text);
}

If we also move the constant messages (the two validation warnings and the "Untitled" caption string) into static class members -

private readonly static NonBlankTrimmedString _defaultCaption
  = new NonBlankTrimmedString("Untitled");

private readonly static NonBlankTrimmedString _noTitleWarning
  = new NonBlankTrimmedString("Must enter a title");

private readonly static NonBlankTrimmedString _noContentWarning
  = new NonBlankTrimmedString("Must enter message content");

.. then we can make the "Title" validation-message-setting/unsetting much clearer:

message = message
  .With(_ => _.Title, Validate(message.Title, MustHaveValue, _noTitleWarning));

If we add a final helper method to make the setting of the "Caption" property simpler -

private NonBlankTrimmedString ToNonBlankTrimmedString(
  TextEditState textEditState,
  NonBlankTrimmedString fallback)
{
  if (textEditState == null)
    throw new ArgumentNullException("textEditState");
  if (fallback == null)
    throw new ArgumentNullException("fallback");

  return (textEditState.Text.Trim() == "")
    ? fallback
    : new NonBlankTrimmedString(textEditState.Text);
}

.. then the "ValidateMessage" can be reduced to the following:

private MessageEditState ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  return message
    .With(_ => _.Caption, ToNonBlankTrimmedString(message.Title, fallback: _defaultCaption))
    .With(_ => _.Title, Validate(message.Title, MustHaveValue, _noTitleWarning))
    .With(_ => _.Content, Validate(message.Content, MustHaveValue, _noContentWarning));
}

Now I really think that we have the best of every world. The actual code in "ValidateMessage" is short and to the point. While there are more lines of code in total (when you also consider the "ToNonBlankTrimmedString", "Validate" and "MustHaveValue" methods), each method is more focused and very easy to fully comprehend at a glance. This is the crux of the matter for me - these changes are all about (say it with, because I'm sure that you know what's coming by this point): making code easier to reason about and hence easier to read, maintain and extend.

In the past, I've had a tendency to interchange the words "method" and "function". For the last year or so (and definitely in this series of posts, I hope!) I've been more careful not to use "function" when I mean "method". Having read around, it seems like the accepted difference between the two is (to quote an excellent example from a StackOverflow answer) -

A function is a piece of code that is called by name. It can be passed data to operate on (ie. the parameters) and can optionally return data (the return value).

All data that is passed to a function is explicitly passed.

A method is a piece of code that is called by name that is associated with an object. In most respects it is identical to a function except for two key differences.

It is implicitly passed the object on which it was called.
It is able to operate on data that is contained within the class (remembering that an object is an instance of a class - the class is the definition, the object is an instance of that data).

That means that C# only has methods since every method is associated with an object. Even static methods are, technically, since they have access to anything else that is static within the type that declares the static method.

A function will only consider data passed explicitly in arguments, which is not a concept that is possible to represent with C#.

The key difference, then, being that a function is absolutely guaranteed to always retun the same value given the same argument(s). Parallels are often drawn to mathematical functions. If you think about the need to "calculate the square root of x", this is a good example of a function as it will always return the same result for any value of "x". "x" is the only thing that matters.

With C#, you can get no such guarantees. Just to really drive the point home, here are three example - first, an instance method:

public class Adder
{
  private readonly int _amountToIncrement;
  public Adder(int amountToIncrement)
  {
    _amountToIncrement = amountToIncrement;
  }

  public int AddTo(int value)
  {
    return value + _amountToIncrement;
  }
}

Obviously, the return value from "AddTo" depends on more than the argument passed in - it also depends upon the "_amountToIncrement" that the Adder instance has.

And a couple of static examples:

public static class Adder
{
  private static int _amountToIncrement = 0;

  public static int AddTo(int value)
  {
    _amountToIncrement++;
    return value + _amountToIncrement;
  }
}

public static class DayNameRetriever
{
  public static string GetDayNameForDateThisMonth(int date)
  {
    var today = DateTime.Now;
    var firstDayOfMonth = today.AddDays(-today.Day).AddDays(date);
    return firstDayOfMonth.ToString("dddd");
  }
}

Granted, theses examples are clearly contrived to illustrate a point and are not genuinely useful code. But they are also not totally unlike code that exists in the real world. The point is that, because C# only has methods, the mental burden in fully comprehending any method is increased because you have to be aware of anything else that the method might have access to.

Which is a pity, because the "ToNonBlankTrimmedString", "Validate" and "MustHaveValue" methods are perfect examples of genuine functions - they only operate on their arguments. The "ValidateMessage" only strays outside of its arguments to access the "default caption", "missing-title validation message" and "missing-content validation message" values, but since there are effectively constants (since they are static readonly instances of immutable types) then "ValidateMessage" could also be considered to be a true function (in particular, we know that it will always return the same data given the same arguments).

Note: Interestingly, there is a [Pure] attribute in the .net framework, which is intended to indicate that a method is a "pure function" (where the phrase "pure function" is effectively consistent with the description of a "function" that I gave above). This seems like a nice idea, but it's not actually enforced by the compiler and so it's more of a suggestion, which greatly reduces my enthusiasm. The reason that I want to use immutable types to represent data that should not change (like React components' props types) is that it encodes the "this data is immutable" information into the type system and results in any code that tries to break this requirement (by trying to set a value on an immutable type, for example) as being identified as an error by the compiler. The [Pure] attribute will, alas, not result in any compiler warnings or errors.

The closest that we can get to indicating that a method should be considered a "function" is by making it static. As I showed above, this does not mean that the method is truly "pure" (at least, there is no provision for the compiler to confirm that this is so) but making a function static does, at least, mean that it can not access any instance fields, properties or methods and so there is still less to consider when reading one of these methods. If you know that a method is static, then there is less mental burden in reading it since you know that there is less code that you need to consider that may possibly affect the current method.

What I'm trying to get at is that the "ValidateMessage", "ToNonBlankTrimmedString", "Validate" and "MustHaveValue" methods should all be made static and, to go further, it's worth writing all methods as static unless you have a compelling reason not to. For a lot of methods, it's obvious that they have to be instance methods - the "Render" methods on the React component classes have to be instance methods, obviously, because they depend upon the "props" data for that component instance. But, in the final MessageWriterStore implementation (see below), if we pull the "OnChange" method into a lambda then there is no need for any of the methods to not be static.

It seems, in general, that people write methods as instance methods by default and then make them static if they encounter a good reason to do so. I suggest that methods be written as static by default and only made into instance methods if there is a good reason to do so.

(To be honest, this is still something that I'm trying to consistently apply to my own work - it's very easy to unconsciously write instance methods by default by omitting the "static" keyword; old habits die hard!)

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Stores
{
  public class MessageWriterStore
  {
    private Optional<RequestId> _saveActionRequestId, _lastDataUpdatedRequestId;
    public MessageWriterStore(IReadAndWriteMessages messageApi, AppDispatcher dispatcher)
    {
      if (messageApi == null)
        throw new ArgumentNullException("messageApi");
      if (dispatcher == null)
        throw new ArgumentNullException("dispatcher");

      Message = GetInitialMessageEditState();
      MessageHistory = NonNullList<Saved<MessageId, MessageDetails>>.Empty;

      dispatcher.Receive(a => a
        .If<StoreInitialised>(
          condition: action => (action.Store == this),
          work: action => { }
        )
        .Else<UserEditRequested<MessageEditState>>(action =>
          Message = ValidateMessage(action.NewState)
        )
        .Else<SaveRequested<MessageDetails>>(action =>
        {
          _saveActionRequestId = messageApi.SaveMessage(action.Data);
          Message = Message.With(_ => _.IsSaveInProgress, true);
        })
        .Else<SaveSucceeded>(
          condition: action => (action.RequestId == _saveActionRequestId),
          work: action =>
          {
            _saveActionRequestId = null;
            Message = GetInitialMessageEditState();
            _lastDataUpdatedRequestId = messageApi.GetMessages();
          }
        )
        .Else<DataUpdated<NonNullList<Saved<MessageId, MessageDetails>>>>(
          condition:
            action => action.RequestId.IsEqualToOrComesAfter(_lastDataUpdatedRequestId),
          work: action =>
          {
            _lastDataUpdatedRequestId = action.RequestId;
            MessageHistory = action.Data;
          }
        )
        .IfAnyMatched(() => { if (Change != null) Change(); })
      );
    }

    public event Action Change;
    public MessageEditState Message { get; private set; }
    public NonNullList<Saved<MessageId, MessageDetails>> MessageHistory { get; private set; }

    private readonly static NonBlankTrimmedString _defaultCaption
      = new NonBlankTrimmedString("Untitled");
    private readonly static NonBlankTrimmedString _noTitleWarning
      = new NonBlankTrimmedString("Must enter a title");
    private readonly static NonBlankTrimmedString _noContentWarning
      = new NonBlankTrimmedString("Must enter message content");

    private static MessageEditState GetInitialMessageEditState()
    {
      return new MessageEditState(
        caption: _defaultCaption,
        title: new TextEditState("", _noTitleWarning),
        content: new TextEditState("", _noContentWarning),
        isSaveInProgress: false
      );
    }

    private static MessageEditState ValidateMessage(MessageEditState message)
    {
      if (message == null)
        throw new ArgumentNullException("message");

      return message
        .With(_ => _.Caption, ToNonBlankTrimmedString(message.Title, _defaultCaption))
        .With(_ => _.Title, Validate(message.Title, MustHaveValue, _noTitleWarning))
        .With(_ => _.Content, Validate(message.Content, MustHaveValue, _noContentWarning));
    }

    private static NonBlankTrimmedString ToNonBlankTrimmedString(
      TextEditState textEditState,
      NonBlankTrimmedString fallback)
    {
      if (textEditState == null)
        throw new ArgumentNullException("textEditState");
      if (fallback == null)
        throw new ArgumentNullException("fallback");

      return (textEditState.Text.Trim() == "")
        ? fallback
        : new NonBlankTrimmedString(textEditState.Text);
    }

    private static TextEditState Validate(
      TextEditState textEditState,
      Predicate<TextEditState> validIf,
      NonBlankTrimmedString messageIfInvalid)
    {
      if (textEditState == null)
        throw new ArgumentNullException("textEditState");
      if (validIf == null)
        throw new ArgumentNullException("validIf");
      if (messageIfInvalid == null)
        throw new ArgumentNullException("messageIfInvalid");

      return textEditState.With(_ => _.ValidationError, validIf(textEditState)
        ? null
        : messageIfInvalid);
    }

    private static bool MustHaveValue(TextEditState textEditState)
    {
      if (textEditState == null)
        throw new ArgumentNullException("textEditState");

      return !string.IsNullOrWhiteSpace(textEditState.Text);
    }
  }
}

Note that, since the RequestId values are now Optional<RequestId> instances, we need to change the "IsEqualToOrComesAfter" extension method -

using System;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.API
{
  public static class RequestIdExtensions
  {
    public static bool IsEqualToOrComesAfter(
      this RequestId source,
      Optional<RequestId> other)
    {
      if (source == null)
        throw new ArgumentNullException("source");

      // If the "other" reference is no-RequestId then the "source" may be considered to
      // come after it
      if (!other.IsDefined)
        return true;

      return (source == other.Value) || source.ComesAfter(other.Value);
    }
  }
}

The rest of the gaps

There's been a lot of theory covered so far. To really put it into practice, though, we need to fix the rest of the compile errors in the example application.

Changing the MessageEditor, MessageHistory, AppContainer and MessageWriteStore to use the new immutable types (the now-immutable MessageDetails and the NonNullList type from ProductiveRage.Immutable) require further changes to the MessageApi and the App file that initialises the application.

And, while we're making everything immutable, let's change the action classes. Currently, we have actions such as:

using Bridge.React;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Actions
{
  public class DataUpdated<T> : IDispatcherAction
  {
    public RequestId RequestId;
    public T Data;
  }
  public static class DataUpdated
  {
    public static DataUpdated<T> For<T>(RequestId requestId, T data)
    {
      return new DataUpdated<T> { RequestId = requestId, Data = data };
    }
  }
}

This should be:

using Bridge.React;
using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Actions
{
  public class DataUpdated<T> : IDispatcherAction, IAmImmutable
  {
    public DataUpdated(RequestId requestId, T data)
    {
      this.CtorSet(_ => _.RequestId, requestId);
      this.CtorSet(_ => _.Data, data);
    }
    public RequestId RequestId { get; }
    public T Data { get; }
  }
  public static class DataUpdated
  {
    public static DataUpdated<T> For<T>(RequestId requestId, T data)
    {
      return new DataUpdated<T>(requestId, data);
    }
  }
}

The others require similar changes -

using Bridge.React;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Actions
{
  public class SaveRequested<T> : IDispatcherAction, IAmImmutable
  {
    public SaveRequested(T data)
    {
      this.CtorSet(_ => _.Data, data);
    }
    public T Data { get; }
  }
  public static class SaveRequested
  {
    public static SaveRequested<T> For<T>(T data)
    {
      return new SaveRequested<T>(data);
    }
  }
}

using Bridge.React;
using BridgeReactTutorial.API;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Actions
{
  public class SaveSucceeded : IDispatcherAction, IAmImmutable
  {
    public SaveSucceeded(RequestId requestId)
    {
      this.CtorSet(_ => _.RequestId, requestId);
    }
    public RequestId RequestId { get; }
  }
}

using Bridge.React;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Actions
{
  public class StoreInitialised : IDispatcherAction, IAmImmutable
  {
    public StoreInitialised(object store)
    {
      this.CtorSet(_ => _.Store, store);
    }
    public object Store { get; }
  }
}

using Bridge.React;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Actions
{
  public class UserEditRequested<T> : IDispatcherAction, IAmImmutable
  {
    public UserEditRequested(T newState)
    {
      this.CtorSet(_ => _.NewState, newState);
    }
    public T NewState { get; }
  }
  public static class UserEditRequested
  {
    public static UserEditRequested<T> For<T>(T newState)
    {
      return new UserEditRequested<T>(newState);
    }
  }
}

The App class requires only minor tweaks, from:

using System.Linq;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.Components;
using BridgeReactTutorial.Stores;

namespace BridgeReactTutorial
{
  public class App
  {
    [Ready]
    public static void Go()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );

      var dispatcher = new AppDispatcher();
      var messageApi = new MessageApi(dispatcher);
      var store = new MessageWriterStore(messageApi, dispatcher);
      React.Render(
        new AppContainer(new AppContainer.Props
        {
          Dispatcher = dispatcher,
          Store = store
        }),
        container
      );
      dispatcher.Dispatch(new StoreInitialised { Store = store });
    }
  }
}

to:

using System.Linq;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.Components;
using BridgeReactTutorial.Stores;

namespace BridgeReactTutorial
{
  public class App
  {
    [Ready]
    public static void Go()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );

      var dispatcher = new AppDispatcher();
      var messageApi = new MessageApi(dispatcher);
      var store = new MessageWriterStore(messageApi, dispatcher);
      React.Render(
        new AppContainer(dispatcher, store),
        container
      );
      dispatcher.Dispatch(new StoreInitialised(store));
    }
  }
}

Finally, the MessageApi needs various alterations to deal with the fact that all data types (such as the MessageDetails, the message history and the action classes) are immutable -

using System;
using Bridge;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    private readonly AppDispatcher _dispatcher;
    private NonNullList<Saved<MessageId, MessageDetails>> _messages;
    public MessageApi(AppDispatcher dispatcher)
    {
      if (dispatcher == null)
        throw new ArgumentException("dispatcher");

      _dispatcher = dispatcher;
      _messages = NonNullList<Saved<MessageId, MessageDetails>>.Empty;

      // To further mimic a server-based API (where other people may be recording messages
      // of their own), after a 10s delay a periodic task will be executed to retrieve a
      // new message
      Window.SetTimeout(
        () => Window.SetInterval(GetChuckNorrisFact, 5000),
        10000
      );
    }

    public RequestId SaveMessage(MessageDetails message)
    {
      return SaveMessage(message, optionalSaveCompletedCallback: null);
    }

    private RequestId SaveMessage(
      MessageDetails message,
      Action optionalSaveCompletedCallback)
    {
      if (message == null)
        throw new ArgumentNullException("message");

      var requestId = new RequestId();
      Window.SetTimeout(
        () =>
        {
          _messages = _messages.Add(Saved.For(
            (MessageId)(int)_messages.Count,
            message
          ));
          _dispatcher.Dispatch(new SaveSucceeded(requestId));
          if (optionalSaveCompletedCallback != null)
            optionalSaveCompletedCallback();
        },
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    public RequestId GetMessages()
    {
      var requestId = new RequestId();
      Window.SetTimeout(
        () => _dispatcher.Dispatch(DataUpdated.For(requestId, _messages)),
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    private void GetChuckNorrisFact()
    {
      var request = new XMLHttpRequest();
      request.ResponseType = XMLHttpRequestResponseType.Json;
      request.OnReadyStateChange = () =>
      {
        if (request.ReadyState != AjaxReadyState.Done)
          return;

        if ((request.Status == 200) || (request.Status == 304))
        {
          try
          {
            var apiResponse = (ChuckNorrisFactApiResponse)request.Response;
            if ((apiResponse.Type == "success")
            && (apiResponse.Value != null)
            && !string.IsNullOrWhiteSpace(apiResponse.Value.Joke))
            {
              // The Chuck Norris Facts API (http://www.icndb.com/api/) returns strings
              // html-encoded, so they need decoding before be wrapped up in a
              // MessageDetails instance
              // - Note: After the save has been processed, GetMessages is called so
              //   that a MessageHistoryUpdate action is dispatched
              SaveMessage(
                new MessageDetails(
                  title: new NonBlankTrimmedString("Fact"),
                  content: new NonBlankTrimmedString(HtmlDecode(apiResponse.Value.Joke))
                ),
                () => GetMessages()
              );
              return;
            }
          }
          catch
          {
            // Ignore any error and drop through to the fallback message-generator below
          }
        }
        SaveMessage(new MessageDetails(
          title: new NonBlankTrimmedString("Fact"),
          content: new NonBlankTrimmedString("API call failed when polling for content :(")
        ));
      };
      request.Open("GET", "http://api.icndb.com/jokes/random");
      request.Send();
    }

    private string HtmlDecode(string value)
    {
      if (value == null)
        throw new ArgumentNullException("value");

      var wrapper = Document.CreateElement("div");
      wrapper.InnerHTML = value;
      return wrapper.TextContent;
    }

    [IgnoreCast]
    private class ChuckNorrisFactApiResponse
    {
      public extern string Type { [Template("type")] get; }
      public extern FactDetails Value { [Template("value")] get; }

      [IgnoreCast]
      public class FactDetails
      {
        public extern int Id { [Template("id")] get; }
        public extern string Joke { [Template("joke")]get; }
      }
    }
  }
}

One pleasant change was the removal of code that was previously in the MessageApi with the following comment:

// ToArray is used to return a clone of the message set - otherwise, the caller would
// end up with a list that is updated when the internal reference within this class
// is updated (which sounds convenient but it's not the behaviour that would be
// exhibited if this was really persisting messages to a server somewhere)

Since the message list is described by an immutable structure, there is no way that a particular reference's data could change. There is no way that a component could have a reference to this data type and then find that the data in that reference had changed by the time that an event bubbled up to that component from one of its child components. Similarly, when the MessageApi passes its message history data out, there is no action that may be performed by any code that receives the message history reference that could "pollute" the data that the MessageApi stores internally.

Previously, when the MessageApi wanted to share its message history data, we had two options - we could hope that the mutable list of mutable MessageDetails would never be manipulated when it was passed out from the MessageApi or we could try to make it impossible for other code to pollute the MessageApi's copy of the data, which is what the "ToArray" call went some way towards (note that this wouldn't have saved us from code that received the mutable message history and then changed one of the fields on any of the individual mutable MessageDetails instances - this would have polluted to MessageApi's internal data).

This is a nice example of how immutable structures can actually aid performance as well as aiding code clarity. Before, we were using a defensive "ToArray" call to try to avoid any silly mistakes polluting the MessageApi's internal data. This was only a partial solution anyway, since, to really protect ourselves, we would have needed to clone the entire list - cloning each individual MessageDetails instance, as well as the list itself. Now that the data is immutable, such cloning (which can be very expensive in some case) is not necessary. I maintain, though, that the biggest benefit is to code clarity rather than performance - it is now impossible to make the "silly mistake" of mutating shared data, because the previously-implicit behaviour guideline of "do not try to mutate this data, please" is now encapsulated in the type system.

It's not uncommon to hear people claim that using immutable types incur a performance cost. I believe that this is only really true at a highly localised level. For example, if you have an array and you want to change the element at index 5, that is an incredibly cheap operation and it is not possible to have an "immutable array" that has a method that will give you a new immutable array instance with a different value at index 5 as cheaply. At this level, mutable structures can perform operations more quickly. However, immutable structures can allow techniques that provide performance benefits at a higher level, such as described above, where expensive cloning operations may be avoided entirely (general-case cloning operations can be expensive in CPU and in memory, since a clone will duplicate the entire data structure, whereas mature immutable-type libraries leverage clever "persistent structures" to reuse data between instances).

(It has become less common to hear this argument against immutable data structures since they are being much more widely used these days - React is an excellent example in that it leverages immutability to allow for fantastic performance, rather than immutability being a cost that the React library has to pay).

While performance is not my number one goal (which is not to say that I don't think it's an important target, I'm just saying that I value code clarity more highly), this topic of conversation leads me nicely on to the next topic.

Pure Components

If a "pure function" is one that returns a value based solely upon its arguments, then a "pure component" is a parallel concept - it generates content based solely upon its "props" data.

To recall what our example application looks like -

Message Editor and Message History

There are basically two parts to it; the Message Editor and the Message History. The Message Editor part changes after one of any of the following occurs -

  1. While the entry form is enabled, the user changes the content in one of the text inputs
  2. While the entry form is enabled and both text inputs have values, the user clicks Save
  3. A save request is completed and the form changes back from disabled to enabled

The Message History part changes only when the MessageApi sends a message to say that there is new message data to display.

What happens in our application is that every change results in a full React re-render. React is very efficient and its Virtual DOM minimises (and can batch) changes to the slow browser DOM, so this is rarely something to worry about. However, it might lead you to think -

If I know that a particular event will only result in changes to the Message Editor, isn't it wasteful to React to re-render the entire Message History content in its Virtual DOM - particularly if it does this only to discover that no changes to the browser DOM need to be applied?

This is an entirely reasonable question. If there are a hundred messages in the Message History, does that component really have to re-render them all in the Virtual DOM every time that the user presses a button to change the value in the "Title" text input in the Message Editor? What if there 1000 messages in the history? Or what if this was a much more complicated application with many, many editable inputs and lists of results all over the page - do I really want the entirety of this complicated UI to be re-rendered by the Virtual DOM every time that the user edits a single field?

If we were using mutable structures to represent the data that the React component hierarchy has to render, we would have a few options. One would be to change the component structure such that there were more stateful components in order to try to only update branches of the hierarchy that need to change according to particular changes. In our example, the MessageEditor could be made stateful in a bid to limit changes to the text inputs from resulting in re-renders of the MessageHistory (which would also have to become a stateful component, so that it could update itself when the message history data changes). This would require the MessageWriteStore to be changed as well. On the surface of it, this doesn't necessarily sound like a terrible idea, but stateful components will always require more thought and planning than stateless components and so this would be a move back towards more complicated component models. This would be an unfortunate step back from where we are now, where the complications are minimised and most components are stateless. We would no longer have a render-down and pass-events-up model, we would have a sort of branched version of it.

Another option would be to try to have components make use of React's "shouldComponentUpdate" method. This is a method that may optionally be implemented on components, that is called before a component's "Render" method is called, so long as that component has been rendered at least once before. It will be given two "props" values - one is the props data from the last render and the second is the new props data that has been specified for the re-render. If this method returns true then the component is re-rendered (to the Virtual DOM) as normal. If it returns false then the component's "Render" method is not called. This would mean that none of its child components would be re-rendered either, since those re-renders are only triggered by code in their parent's component's "Render" method. If it was possible for the MessageHistory to look at its last props and its next props and see that they describe the same data, then the entire re-render work could be avoided. The problem comes in working that out, though - for the cases where the old and new messages data was the same and when we had an IEnumerable set of mutable MessageDetails instances, we would have had to have enumerated through every value in the set and compared the "Title" and "Content" values on each message. If they all matched then the old and new data would have been proven to have been the same and the re-render would not be required. But was all that comparison work really much cheaper than just letting the Virtual DOM do its magic?

One of the good thing about immutable structures is that data can safely be shared and reused. Now that the MessageHistory component takes an immutable NonNullList of immutable MessageDetails instances, if the data hasn't changed then the same NonNullList<Saved<MessageId, MessageDetails>> reference will be passed to the MessageHistory.Props instance - but if the data has changed then, by necessity, a new NonNullList<Saved<MessageId, MessageDetails>> reference will be provided. This would make a "shouldComponentUpdate" implementation very simple - just look at each property on the old and new props references and use reference equality comparisons to see if anything's changed.

The bad news is that the StatelessComponent base class in the Bridge / React bindings doesn't support "shouldComponentUpdate". So you can't try to take advantage of it to reduce the work that the Virtual DOM does - only the Component (which is the full stateful component) base class supports it. The good news is that you don't need to implement it manually. If you're creating stateless components whose props classes have properties that are all primitive values (such as bool, int, string, etc..) and / or immutable types and / or functions* and if the components genuinely render entirely according to the props data (no accessing DateTime.Now, for example) then you can derive from the PureComponent base class instead. This automatically implements "shouldComponentUpdate" behind the scenes.

* (There are some cases where "props" properties that are callbacks - like "OnChange" on the TextInput - can't be compared by the PureComponent's magic, but most of the time they can be and the details of when they can and can't are outside the scope of this article - so let's just assume that function / Action<T> / callback property types CAN always be handled).

To illustrate, add the following line to the start of the MessageHistory "Render" method -

Console.WriteLine("MessageHistory.Render");

Now, run the application in the browser and bring up the browser console in the dev tools. Every time that the app re-renders in the Virtual DOM, "MessageHistory.Render" will be written to the console. Every time that a key is pressed to change one of the text input elements, the entire UI will be re-rendered and "MessageHistory.Render" will be displayed in the console.

Now, change the base class of the MessageHistory from StatelessComponent<MessageHistory.Props> to PureComponent<MessageHistory.Props>. It will look like this:

using System;
using System.Linq;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class MessageHistory : StatelessComponent<MessageHistory.Props>
  {
    public MessageHistory(
      NonNullList<Saved<MessageId, MessageDetails>> messages,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, messages)) { }

    public override ReactElement Render()
    {
      Console.WriteLine("MessageHistory.Render");

      var className = props.ClassName;
      if (!props.Messages.Any())
        className = className.Add(" ", new NonBlankTrimmedString("zero-messages"));

      // Any time a set of child components is dynamically-created (meaning that the
      // numbers of items may vary from one render to another), each must have a unique
      // "Key" property set (this may be a int or a string). Here, this is simple as
      // each message tuple is a unique ID and the contents of that message.
      var messageElements = props.Messages
        .Select(savedMessage => DOM.Div(new Attributes { Key = (int)savedMessage.Key },
        DOM.Span(new Attributes { ClassName = "title" }, savedMessage.Value.Title),
        DOM.Span(new Attributes { ClassName = "content" }, savedMessage.Value.Content)
        ));

      // When child components are specified (as they are through the second argument of
      // DOM.Div), the argument is of type Union<ReactElement, string>[] (meaning that each
      // element may be another component or it may be a simple text value)
      // - The React  bindings have an extension method that transforms an IEnumerable set
      //   of components (such as "messageElements") into an Union<ReactElement, string>[]
      return DOM.FieldSet(
        new FieldSetAttributes { ClassName = className.ToStringIfDefined() },
        DOM.Legend(null, "Message History"),
        DOM.Div(null, messageElements)
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        NonNullList<Saved<MessageId, MessageDetails>> messages)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Messages, messages);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public NonNullList<Saved<MessageId, MessageDetails>> Messages { get; }
    }
  }
}

Re-build the application and refresh it in the browser. Now change the text input values while keeping an eye on the console. The "MessageHistory.Render" message will initially only appear in the console when the MessageHistory component is first rendered, the changes to the text inputs no longer require the MessageHistory component be redrawn by the Virtual DOM. When the message data actually changes (whether due to you saving a new message or due to a new Chuck Norris fact arriving), the MessageHistory component will update - indicated by another "MessageHistory.Render" message being displayed in the console.

This is an excellent example of how using immutable structures can result in cleaner and more efficient code. In a complicated UI (or if your application is very performance-sensitive - if you're trying to achieve 60fps on mobile, for example) then being able to save the Virtual DOM the work of determining whether entire branches of the component hierarchy should be re-rendered is invaluable. And getting this optimisation "for free" makes it even better - if you're following my recommendations and the vast majority of your React components are stateless and al of your data types are immutable then you might as well use the PureComponent base class and reap the performance benefits.

PureComponent details

I want to go into some of the finer point of the PureComponent's optimisation rules. There's nothing particularly complicated or surprising, but there are some nuances that it's worth being aware of.

When the PureComponent implements "shouldComponentUpdate" behind the scenes, the React library provides it with two separate instances to compare of the Props class for the current component. The first thing that the PureComponent does is ensure that the two props instances are of the same type (while it would be strange, it would not be illegal to create types derived from the component's Props class - but if different derived types were provided for the old and new props then it doesn't seem safe to try to compare them, who knows why they are different or what significance there could be in the differences). If the old and new props references are of the precise same type, then it enumerates the properties on the type and compares the values on the old and new props instances. Each pair of property values must match - this means that they are either both null or they are both the same value of a primitive type or they are the same reference or they are both non-null and the first value has an "Equals" method that returns true when the second value is passed into it.

On the whole, this means that things largely work completely intuitively. Particularly due to the way that the "With" extension methods works for IAmImmutable-implementing class. If "With" is called with a property value update where the new value is the same as the old value, then "With" returns the original instance unaltered. This is most easily explained with an example:

var title = new TextEditState(text: "hello", validationError: null);
var title2 = title.With(_ => _.Text, "hello");
var title3 = title.With(_ => _.Text, "hell");

The "title2" instance will be the same as the "title" reference - the text value was asked to changed from "hello" to "hello", which is no change at all. Since the TextEditState type is immutable, there is no pointing copying "title" to create a new "title2" reference with all of the same data. "title3" will be a new instance, since the text value needs to change from "hello" to "hell".

Having "With" return the same reference when no change is required is beneficial for garbage collection - the fewer references that are created means the less work that it has to do. But it's also very important for the PureComponent since that prefers to use referential equality to determine whether a property value has changed. If a Props class has a TextEditState property on it, when the values on the old and new props are compared then we want the TextEditState references to be the same if the data that they represent hasn't changed.

I think that another example is called for. In the example application from this series, the Message Editor form is given information in its props that describes the current state of the form - the "Caption", the "Title" text-input-value-and-any-validation-message, the "Content" text-input-value-and-any-validation-message (and information about whether the form should be disabled because a save is in progress). This data is all contained within a MessageEditState instance. The MessageEditor component renders each text input by generating child ValidatedTextInput components. These child ValidatedTextInput components raise an "OnChange" event when the user wants to alter the content in the text input element, the event includes a string argument for the new text value. When this happens, the MessageEditor takes this new text value and uses it to create a new MessageEditState instance, using the "With" extension method - this new instance is then passed up on the MessageEditor's "OnChange" event. This event will result in the UI being re-rendered to display the new data.

However, React raises change events from text inputs for user interactions even if they don't actually result in a change. If, for instance, there is a text input with the value "Hello" in it and you highlight that text and copy it to the clipboard and then paste it into that same text input then the value obviously hasn't changed, but React still raises a change event from the text input due to the paste action. What we want to happen in this case is for the "new" MessageEditState instance that the MessageEditor creates when it raises its "OnChange" event to be the exact same reference as the MessageEditState given to the MessageEditor when it last rendered. This way, when the MessageEditor is asked to re-render then it will find that the "new" props data is exactly the same as the old props data and the PureComponent logic will tell React that it needn't bother re-rendering the component at all.

Maybe it's worth examining the MessageEditor code again to try to make this seem less abstract:

using System;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;
using ProductiveRage.Immutable;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(
      MessageEditState message,
      Action<MessageEditState> onChange,
      Action onSave,
      Optional<NonBlankTrimmedString> className = new Optional<NonBlankTrimmedString>())
      : base(new Props(className, message, onChange, onSave)) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        props.Message.Title.ValidationError.IsDefined ||
        props.Message.Content.ValidationError.IsDefined;

      return DOM.FieldSet(
        new FieldSetAttributes { ClassName = props.ClassName.ToStringIfDefined() },
        DOM.Legend(null, props.Message.Caption),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(
          className: new NonBlankTrimmedString("title"),
          disabled: props.Message.IsSaveInProgress,
          content: props.Message.Title.Text,
          onChange: newTitle => props.OnChange(
            props.Message.With(_ => _.Title, new TextEditState(newTitle))
          ),
          validationMessage: props.Message.Title.ValidationError
        ),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(
          className: new NonBlankTrimmedString("content"),
          disabled: props.Message.IsSaveInProgress,
          content: props.Message.Content.Text,
          onChange: newContent => props.OnChange(
            props.Message.With(_ => _.Content, new TextEditState(newContent))
          ),
          validationMessage: props.Message.Content.ValidationError
        ),
        DOM.Button(
        new ButtonAttributes
        {
          Disabled = formIsInvalid || props.Message.IsSaveInProgress,
          OnClick = e => props.OnSave()
        },
        "Save"
        )
      );
    }

    public class Props : IAmImmutable
    {
      public Props(
        Optional<NonBlankTrimmedString> className,
        MessageEditState message,
        Action<MessageEditState> onChange,
        Action onSave)
      {
        this.CtorSet(_ => _.ClassName, className);
        this.CtorSet(_ => _.Message, message);
        this.CtorSet(_ => _.OnChange, onChange);
        this.CtorSet(_ => _.OnSave, onSave);
      }
      public Optional<NonBlankTrimmedString> ClassName { get; }
      public MessageEditState Message { get; }
      public Action<MessageEditState> OnChange { get; }
      public Action OnSave { get; }
    }
  }
}

If the user attempted this copy-paste-same-value thing in the "Title" input, then the "onChange" event from the ValidatedTextInput that renders the Title value would be raised -

onChange: newTitle => props.OnChange(
  props.Message.With(_ => _.Title, new TextEditState(newTitle))
)

This will result in the MessageEditor's "OnChange" event being raised, with a new MessageEditState instance. The key thing is that we want the new MessageEditState instance to be the same as the current MessageEditState instance if the new "Title" string is exactly the same as the current "Title" string.

One way to do this would be to not worry about how "With" does or doesn't work and to add a condition into the lambda - eg.

onChange: newTitle =>
{
  if (newTitle != props.Message.Title.text)
    props.OnChange(props.Message.With(_ => _.Title, new TextEditState(newTitle)));
}

However, this means that more logic has to go in the components (which I want to avoid). Worse, it's boring and repetitive logic, which is the kind that I find is most likely to be done incorrectly by accident because you almost feel like you can write it on auto-pilot. It would be best if this could be handled automatically.

Well, it can be if we always use "With" to update values. In the code above, I've actually been a bit naughty. A TextEditState includes two values - "Text" and "ValidationMessage". The "ValidationMessage" will get set according to the "Text" value when validation is applied (which happens in the MessageWriterStore in this application). The code above creates a new TextEditState with the "newTitle" string, erasing any "ValidationMessage" value. This is not really correct, since only the validation logic should change the "ValidationMessage" value. In this example, a validation message should only be displayed if the text value is empty - but the components should have no knowledge of this since we want them to be as dumb as possible. So, any time that a component creates a new TextEditState to include in an "OnChange" event, the "ValidationMessage" property should be untouched - again, it is the responsibility of the store (and not the component) to worry about ensuring that the "ValidationMessage" value is correct for the "Text" value before a re-render is triggered.

So, this code:

onChange: newTitle => props.OnChange(
  props.Message.With(_ => _.Title, new TextEditState(newTitle))
)

should really be this:

onChange: newTitle => props.OnChange(
  props.Message.With(_ => _.Title, props.Message.Title.With(_ => _.Text, newContent))
)

This only changes the "Text" property on the "Title" TextEditState - which means that, in our copy-paste-same-value case, no new TextEditState instance will be created. This still means that the MessageEditor's "OnChange" event will be raised (which will result in an action being sent through the Dispatcher and received by the MessageWriterStore, which will raise a "Change" event and cause the AppContainer to re-render the UI), but when the MessageEditor is asked to re-render then it will realise that the new data is the same as its current data and it will tell React not to bother re-rendering it. The code still had to do one full pass of the raise-event-up-to-top-level-component-and-send-change-message-through-Dispatcher-to-the-Store, even though the data hadn't changed, but that sort of work is very cheap (certainly much cheaper than any DOM or even Virtual DOM interactions).

All of the above came "for free" by using IAmImmutable-implementing classes and PureComponent and by applying updates using the "With" extension method. There are some cases where you need to do a little work to help the system out, though. If you recall the "ValidateMessage" function that we wrote earlier -

private static MessageEditState ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  return message
    .With(_ => _.Caption, ToNonBlankTrimmedString(message.Title, fallback: _defaultCaption))
    .With(_ => _.Title, Validate(message.Title, MustHaveValue, _noTitleWarning))
    .With(_ => _.Content, Validate(message.Content, MustHaveValue, _noContentWarning));
}

This always set the "Caption" based upon the "Title" value. If there is a "Title" value in the text input of the message editor form of "My New Message" then the "Caption" value will also be "My New Message". The "ToNonBlankTrimmedString" method is implemented as:

private static NonBlankTrimmedString ToNonBlankTrimmedString(
  TextEditState textEditState,
  NonBlankTrimmedString fallback)
{
  if (textEditState == null)
    throw new ArgumentNullException("textEditState");
  if (fallback == null)
    throw new ArgumentNullException("fallback");

  return (textEditState.Text.Trim() == "")
    ? fallback
    : new NonBlankTrimmedString(textEditState.Text);
}

Every time that "ValidateMessage" is called and there is a non-blank "Title" value then a new NonBlankTrimmedString instance will be created for the "Caption". The problem is that if the "Title" input isn't changing (if the user is currently changing the "Content" text input box, for example) then we will be creating new NonBlankTrimmedString instances for the same "Title" value - and the PureComponent will see each new NonBlankTrimmedString reference as a new and distinct value.

We could try to prevent this by changing "ValidateMessage" such that it tries to avoid creating new NonBlankTrimmedString instances for the Caption -

private static MessageEditState ValidateMessage(MessageEditState message)
{
  if (message == null)
    throw new ArgumentNullException("message");

  if (message.Title.Text.Trim() == "")
    message = message.With(_ => _.Caption, _defaultCaption);
  else if (message.Title.Text.Trim() != message.Caption)
    message = message.With(_ => _.Caption, new NonBlankTrimmedString(message.Title.Text));

  return message
    .With(_ => _.Title, Validate(message.Title, MustHaveValue, _noTitleWarning))
    .With(_ => _.Content, Validate(message.Content, MustHaveValue, _noContentWarning));
}

.. but this brings us back round to "ValidateMessage" being very noisy. This will have a tendency to make it prone to error and it definitely moves away from the goal of code clarity that I'm aiming for.

An alternative is to implement an "Equals" override for the NonBlankTrimmedString class. The "With" extension method, like the PureComponent's "shouldComponentUpdate" logic", will consider an "Equals" method if referential equality fails. This means that if we call

.With(_ => _.Caption, ToNonBlankTrimmedString(message.Title, fallback: _defaultCaption))

.. and if the return value from "ToNonBlankTrimmedString" is a NonBlankTrimmedString instance that is equivalent to the current "Caption" value (according to the NonBlankTrimmedString "Equals" implementation below), then "With" will return the same reference.

using System;
using Bridge;
using Bridge.React;

namespace BridgeReactTutorial.API
{
  public sealed class NonBlankTrimmedString
  {
    public NonBlankTrimmedString(string value)
    {
      if (string.IsNullOrWhiteSpace(value))
        throw new ArgumentException("Null, blank or whitespace-only value specified");

      Value = value.Trim();
    }

    /// <summary>
    /// This will never be null, blank or have any leading or trailing whitespace
    /// </summary>
    public string Value { get; }

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a string
    /// </summary>
    public static implicit operator string(NonBlankTrimmedString value)
    {
      if (value == null)
        throw new ArgumentNullException("value");
      return value.Value;
    }

    /// <summary>
    /// It's convenient to be able to pass a NonBlankTrimmedString instance as any argument
    /// that requires a ReactElement-or-string, such as for the children array of the React
    /// DOM component factories
    /// </summary>
    public static implicit operator Union<ReactElement, string>(NonBlankTrimmedString value)
    {
      if (value == null)
        throw new ArgumentNullException("value");
      return value.Value;
    }

    public override bool Equals(object o)
    {
      var otherNonBlankTrimmedString = o as NonBlankTrimmedString;
      return
        (otherNonBlankTrimmedString != null) &&
        (otherNonBlankTrimmedString.Value == Value);
    }

    public override int GetHashCode()
    {
      return Value.GetHashCode();
    }
  }
}

Having an "Equals" implementation on types such as NonBlankTrimmedString makes a lot of sense because we essentially want them to be treated as "value types" - if two references describe the same data then they should be treated as the same value. Note that a custom "Equals" implementation was not necessary for MessageId, since that is a struct - in C#, structs automatically get an "Equals" implementation created for them that considers two struct instances to be equivalent if all of their properties have the same values and the JavaScript generated by Bridge does the same in order to maintain compatibility.

One thing that I snuck into the new NonBlankTrimmedString above is that the class is now sealed. If it is possible to inherit from a given class, it becomes much more difficult to implement a reliable "Equals" method. For the sake of argument, imagine a class "X" that is not sealed and that has a single string "Value" property and that implements its own "Equals" method, exactly the same as the NonBlankTrimmedString "Equals" method above. Then imagine that a class "Y" is derived from "X" and adds a second property, a "Count" int. If "Y" does not override the "Equals" implementation on "X" then it seems likely that the "Equals" implementation that "Y" inherits from "X" will be inaccurate - if an instance of "Y" with a "Value" of "Hello" and "Count" of 1 was compared to another instance of "Y" with a "Value" of "Hello" but a "Count" of 2 then they would be considered to be equivalent, which would almost certainly not be the expected behaviour. There is an implicit assumption that if "X" is derived from and the derived type adds properties then that derived type should have its own "Equals" method. A failure to respect this implicit assumption will not result in any compiler warnings, it will likely result only in unexpected runtime behaviour at some point. I don't like implicit assumptions, as I'm sure that you've been able to tell from the themes in this post. An easy way to avoid this problem is to prevent "X" from being inherited from, by making it sealed. This is precisely what I've done with the NonBlankTrimmedString.

This leads me on to another guideline - I believe that 99% of all classes should be abstract or sealed. Any class that may be inherited from requires planning, to try to make it as easy as possible for any derived types to work in non-suprising manners. This is complicated, if not impossible (as the "Equals" conundrum above hopefully illustrates for an extremely simple case). However, if you really think that it should be possible for a class to be inherited from, then I think that you should document any implicit assumptions on that base class and you should carefully think about how it should and shouldn't be used. I have found that the most common cases for which a base class are suitable are those where some shared functionality is required that can't easily be provided via composition (which I will talk about in a moment), but where that base class is not fully-functional itself and so must be inherited from in order to be useful. The Component, StatelessComponent and PureComponent base classes in the Bridge / React bindings are excellent examples; they are required in order to define components that the React library can work with, but the classes are not functional on their own - they must be inherited from in order to be useful, therefore they are defined as abstract classes.

Historically, I think that there have been beliefs that many object models lend themselves well to inheritance hierarchies. In Web Forms (if I remember correctly - it's been a long time), a Button inherited from a WebControl and that inherited from a Control or a Component.. or something. The idea was that every component as you went up the hierarchy was a specialisation of the one below it. Which arguably made sense. But I find that the waters often get very murky when these "is-a" hierarchies are constructed and it's very easy to confuse a "has-a" characteristic for being an "is-a". For example, the MessageWriterStore needs to register for events from the Dispatcher, so perhaps it is a specialisation of a "DispatcherMessageReceiver". But it's also responsible for saving messages, so perhaps it's also specialisation of a "MessageRecorder". Not only is it more complicated to design classes that are intended to be inherited from, but C# only allows one class to inherit from a single base class - so if MessageWriterStore needs to be a specialisation of both a "DispatcherMessageReceiver" and a "MessageRecorder" then we have a problem; possibly only solved by creating a specialisation of the "DispatcherMessageReceiver" that also deals with recording messages, so that the MessageWriterStore can inherit from that.

Perhaps that example is a little fatuous, but similar sorts of issues do genuinely occur when inheritance trees are viewed as "the best way" to build classes. The alternative is to use composition, which is where classes are designed in a "has-a" manner. The current MessageWriterStore is designed in this way as its constructor declares that it requires an AppDispatcher and a IReadAndWriteMessages implementation. Not only does composition avoid the multiple inheritance problem (also known as the "deadly diamond of death") but it makes code easier to fully comprehend. With inheritance, each class is a sum of its behaviour and all of the behaviour of its base class (which is likewise a sum of its behaviour and all of the behaviour of its base class, repeated for as many levels as the inheritance tree is deep). With composition, each piece is fully self-contained and communication between one part and another is throughly tightly constrained interfaces.

(A couple of months ago, I read "5 reasons your team will love you for composition", which I think offers a good take on some of the practical benefits positives of preferring composition to inheritance - it's well worth a quick read).

In summary, I strongly believe that almost all relations between classes may be described better by using composition than inheritance (where "better" means that the code is easier to reason about and, also, easier to test) and so almost no classes should need to be inherited from. In the few cases where inheritance is necessary, the base classes must be carefully designed for inheritance and the use cases that necessitate inheritance will almost always be ones where the base classes are non-functional in isolation, where they require a derived type in order to work.

Therefore, 99% of classes should be written to be abstract or to be sealed. This goes for all classes that I've shown code for in this series - the MessageEditor component class should be sealed, its Props class should be sealed, the MessageWriterStore should be sealed, the MessageDetails should be sealed, the Saved class should be sealed and the NonBlankTrimmedString should be sealed. They should all be sealed.

Now, if we wanted to play devil's advocate then we could say that any "ClassName" property on a component class shouldn't be Optional<NonBlankTrimmedString> since I've said that everything should be really specific, since richer types have a lot of value in expressing intent. We could say that there should be a more specific ClassName class, which only allows characters that are valid in an html class name (React deals with encoding string "ClassName" properties, so this isn't really a big concern - but I'm trying to prove another point, so bear with me). We could also say that this ClassName class really is a specialisation of NonBlankTrimmedString and so surely we should allow NonBlankTrimmedString to be inherited from so that ClassName could be derived from it. On the surface, this doesn't seem too unreasonable. However, the only actual benefit of having ClassName inherit from NonBlankTrimmedString (other than it just feeling like something that may possibly be a good idea) would be if there was a point at which you had a method that took an argument of type NonBlankTrimmedString that you wanted to give a ClassName instance - because it seems like any valid ClassName will also be a valid NonBlankTrimmedString. I think that the benefit is just too small to outweight the cost. Inheritance brings with it too much potential complication (and associated mental burden) that any small benefit like this is not enough to bring inheritance into play. On top of which, if you really did want to be able to use a ClassName instance anywhere that a NonBlankTrimmedString is required, you could do this by implementing an implicit operator method on ClassName that allows it be implicitly cast to a NonBlankTrimmedString - then you would have the marginal benefit of being able to use a ClassName anywhere that you need a NonBlankTrimmedString but still be able to keep NonBlankTrimmedString sealed and less prone to error.

Writing classes that are sealed by default is another practice that I am still trying to instill into myself. Much like writing methods to be static by default, I think that it makes a huge amount of sense but it's also a concept that I've only cemented in the last year or so and I'm still trying to consistently apply it!

In summary

This has turned out to be a pretty huge post. But I didn't want to try to split it up because all of the principles are related, really.

If you'd stopped reading after Part Two then I think that you would have the tools to construct client-side applications that will scale from something simple up to something massively complex. The combination of C# (which is time-proven as a language that not only enables large applications to be built and maintained over long periods of time, it is a language where it is not exceptional for this to be the case*) and React is very powerful.

* (Languages such as PHP and JavaScript CAN be used to build and maintain large code bases, but I think that it's telling that the companies that take this work seriously rely on, and develop, additional tooling to make it manageable, like Hack and Flow).

However, the principles behind React that I found most appealing when I first encountered it - that it primarily exists to make complicated interactions in an application simpler and scalable - are what I want to apply to my C#. In the concepts that I'm advocating here for writing C# React applications and in React itself, performance is not the number one priority; it is not something for which code clarity must be sacrificed in order to attain. Performance is, however, still important - but it is achieved through high-level design decisions and not through micro-optimisations (I still think that the best example of this is how performing particular operations on an immutable structure will almost always be slower than on the corresponding mutable structure, but the algorithms that may be written based upon the safe sharing of immutable types mean that actual application performance will be greater - whether this is in the avoidance of deep-cloning references for safety or in the way that the PureComponent can avoid re-rendering of entire branches of the UI by the Virtual DOM).

To summarise, I believe that if the guidelines presented here are followed then you will be able to go beyond the C# React applications that you would have written with Part-Two Knowledge and be able to write code that is easier to understand (whether by other Developers or by yourself, when you come back to a piece of code after six months), easier to maintain and extend and that is more efficient.

To recap, the guidelines are as follows:

  1. Immutable data types are fantastic for code clarity (the classes themselves will require more lines of code than if they were mutable but this is a trade-off that is well worth making, plus you will often require less code in places that makes use of these classes - which is relevant if lines of code is the most important metric to you)
  2. Anything that can't be immutable should have accessibility that is as restricted as possible (Store classes are not immutable, but their public properties are all read-only)
  3. Implicit assumptions are "silly mistakes" waiting to happen, encoding as much in the type system as possible communicates intent to other Developers and moves various types of error from runtime to compile time (immutable types and strongly-typed IDs are both examples of this)
  4. Write static methods by default, only make them instance / non-static methods if and when they need to be
  5. Write sealed classes by default, if they really need to be inheritable then they likely should be abstract (classes should almost never be neither sealed nor abstract)
  6. Using simple composable abstractions can greatly improve code clarity (as we saw with the "ValidateMessage" method rewrite)
  7. Code clarity is king!

I'm not sure that there's anything earth-shatteringly original about any one of these suggestions. Combining them can, in my ever-so-humble opinion, result in significantly higher quality code than not following them. While these posts have been about writing React applications using Bridge.NET, these rules may be applied just as well to any C# code. The ProductiveRage.Immutable NuGet package only works with Bridge projects, though - but if anyone asked them I would happily consider recreating it for vanilla C#! :)

Is this really the end??

There are some other things to consider when writing complete Bridge / React applications. I keep saying that it's important for code to be testable, but I haven't offered any way to write the actual unit tests. I've also not had to offer any URL-routing capabilities, since the example application is so simple. But routing is something that is almost certainly going to be required in any real browser-based application.

These are both technologies that I would like to cover in future posts, but probably as shorter follow-up pieces. In terms of how to write React applications in C#, I am happy with what I've covered in these three posts - I wanted to get the example code to where it is now but without jumping straight to the final architecture; I wanted to illustrate why one-way data binding is so beneficial and then why a Flux-like structure is so helpful and then why immutable types are such a good idea. Hopefully, by starting from the basics and introducing new concepts and approaches only when there was a way to illustrate the improvements that they yield, you all agree with me that this is the way to do things!

Of course, if you disagree in general, or on any particular points, or you have any tweaks to what I've suggested then I would be very interested to hear. That's what the comments section is for!

Posted at 21:32

Comments

Writing React apps using Bridge.NET - The Dan Way (Part Two)

To summarise where we got to in Part One: we've got an entry form where, after you enter Title and Content values, you may save a message. During the message-saving process, the form and save button are disabled. Once the saving has completed, the form will be cleared and it will be re-enabled. Validation logic in the MessageEditor prevents the form from being saved while one or both of the required inputs are without value. After the save has succeeded, a read action will begin in the background - once the read operation has completed, a MessageHistory component will display all of the saved messages. All interactions with the MessageApi are handled by the top-level AppContainer component. Similarly, all user interaction events are passed up to this top-level component, from where re-renders of the UI state are triggered.

I see this arrangement as a top-to-bottom tree in terms of rendering - the top-level component is in control of what to display in the component hierarchy beneath it, and all of the information required to display those child components is contained within the top-level component's state data.

In terms of event-handling, events may occur deep down within the tree and are then passed back up to the top-level component. As an event passes up from the html element that it originates in, up to the top level, it will gather more and more information - for example, when a user requests a change to the "Title" text input (such as by pressing a key while the input has focus), then an event is raised by the TextInput component saying that a string value should be changed. This TextInput is a child component of the MessageEditor, which acknowledges this string-changed event and raises it own event; a MessageDetails-changed event. The "Content" value of this new message will be unchanged, but the "Title" value will have a new value - the new value that the TextInput should take. This event is received by the AppContainer and it uses it to update its internal representation of the application, changing its "state" reference by calling "SetState" and so triggering a re-render.

The path may be traced downward when considering rendering and may be traced upward when considering events.

This one-way passing of data is very powerful in terms of modelling interactions that are easy to follow. As a reminder, a common way to deal with interactions like this in days gone by (ie. before React popularised "one-way bindings") was for changes to elements to be reflected immediately in-place and for any interested parties to subscribe to events that those elements raise after they change. So, for the message entry form -

The proposed example app

With the old method, the "Title" and the "Content" inputs would accept changes that the user makes immediately - and the fieldset legend and the save button components would need to listen out to some of these changes. The legend changes to match what is entered in the "Title" input (unless it's blank, in which case the legend shows "Untitled"). The save button needs to be enabled if both "Title" and "Content" have values and disabled if one or both of them are without.

I mentally envisage this as star-shaped event handling - a change to one element may fan out to many others. In some cases, these changes would then cascade on to other elements, and then on again and again (hopefully not "again and again and..", but it was difficult to keep a handle on these things with this sort of approach - because it was difficult to get a simple view as to what could affect what).

With one-way data binding, events go up to the top, are processed and then the re-render distributes this new information all the way down. When the MessageEditor is rendered, it knows what the current "Title" value is and so it knows what to put in that "Title" TextInput and it knows what the fieldset legend should be and it knows whether the save button should be enabled or not.

This arrangement can take you a long way, I think. But there are a couple of things that I take issue with -

  1. I want to be able to easily unit test logic in my application and, while the React library goes a long way to taming the DOM, testing UI components will never be as easy as testing "pure" JavaScript (well, pure C# with Bridge, that will become pure JavaScript) - consequently, I want to be able to extract as much logic out of the UI components as possible
  2. If any more event sources are added to the application, then dealing with these events becomes awkward - another "event source" may, for example, be something in the persistence layer that polls for new data from other users (which might not be uncommon since we're creating web applications and these are commonly expected to be multi-user, so it's beneficial to be able to reflect changes made by other users)

We can refine this arrangement a little by introducing an intermediary for events to pass through and by pulling out the logic that exists within components (such as the validation within the MessageEditor and the when-a-save-happens-then-.. logic in the AppContainer).

From up-and-down to round-and-round

Rather than talk about how some applications could theoretically benefit from a change to the architecture, I want to do it with a demonstration.

I'm going to change the MessageApi so that, after a short delay, new messages start appearing in its internal list. The "SaveMessage" and "GetMessages" methods are unchanged, it's just that there's a background process going on as well. To keep things interesting, I'm going to source these message from the The Internet Chuck Norris Database API -

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bridge;
using Bridge.Html5;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    private readonly List<Tuple<int, MessageDetails>> _messages;
    public MessageApi()
    {
      _messages = new List<Tuple<int, MessageDetails>>();

      // To further mimic a server-based API (where other people may be recording messages
      // of their own), after a 10s delay a periodic task will be executed to retrieve a
      // new message
      Window.SetTimeout(
        () => Window.SetInterval(GetChuckNorrisFact, 5000),
        10000
      );
    }

    public Task SaveMessage(MessageDetails message)
    {
      if (message == null)
        throw new ArgumentNullException("message");
      if (string.IsNullOrWhiteSpace(message.Title))
        throw new ArgumentException("A title value must be provided");
      if (string.IsNullOrWhiteSpace(message.Content))
        throw new ArgumentException("A content value must be provided");

      var task = new Task<object>(null);
      Window.SetTimeout(
        () =>
        {
          _messages.Add(Tuple.Create(_messages.Count, message));
          task.Complete();
        },
        1000 // Simulate a roundtrip to the server
      );
      return task;
    }

    public Task<IEnumerable<Tuple<int, MessageDetails>>> GetMessages()
    {
      // ToArray is used to return a clone of the message set - otherwise, the caller would
      // end up with a list that is updated when the internal reference within this class
      // is updated (which sounds convenient but it's not the behaviour that would be
      // exhibited if this was really persisting messages to a server somewhere)
      var task = new Task<IEnumerable<Tuple<int, MessageDetails>>>(null);
      Window.SetTimeout(
        () => task.Complete(_messages.ToArray()),
        1000 // Simulate a roundtrip to the server
      );
      return task;
    }

    private void GetChuckNorrisFact()
    {
      var request = new XMLHttpRequest();
      request.ResponseType = XMLHttpRequestResponseType.Json;
      request.OnReadyStateChange = () =>
      {
        if (request.ReadyState != AjaxReadyState.Done)
          return;

        if ((request.Status == 200) || (request.Status == 304))
        {
          try
          {
            var apiResponse = (ChuckNorrisFactApiResponse)request.Response;
            if ((apiResponse.Type == "success")
            && (apiResponse.Value != null)
            && !string.IsNullOrWhiteSpace(apiResponse.Value.Joke))
            {
              // The Chuck Norris Facts API (http://www.icndb.com/api/) returns strings
              // html-encoded, so they need decoding before be wrapped up in a
              // MessageDetails instance
              SaveMessage(new MessageDetails
              {
                Title = "Fact",
                Content = HtmlDecode(apiResponse.Value.Joke)
              });
              return;
            }
          }
          catch
          {
            // Ignore any error and drop through to the fallback message-generator below
          }
        }
        SaveMessage(new MessageDetails
        {
          Title = "Fact",
          Content = "API call failed when polling for server content :("
        });
      };
      request.Open("GET", "http://api.icndb.com/jokes/random");
      request.Send();
    }

    private string HtmlDecode(string value)
    {
      if (value == null)
        throw new ArgumentNullException("value");

      var wrapper = Document.CreateElement("div");
      wrapper.InnerHTML = value;
      return wrapper.TextContent;
    }

    [IgnoreCast]
    private class ChuckNorrisFactApiResponse
    {
      public extern string Type { [Template("type")] get; }
      public extern FactDetails Value { [Template("value")] get; }

      [IgnoreCast]
      public class FactDetails
      {
        public extern int Id { [Template("id")] get; }
        public extern string Joke { [Template("joke")]get; }
      }
    }
  }
}

The Chuck-Norris-fact-retrieval code could be made shortener by casting the "apiResponse" reference to dynamic, but I thought that it would a nice opportunity to show how you can call a JSON-returning API with Bridge and then access the data through a known object model (which is why I created a ChuckNorrisFactApiResponse class to use instead).

Without any other changes to the code we have so far, this works.. in a manner of speaking. Any time you save a message of your own, the read action that follows the save will pull back all of the messages from the MessageApi's in-memory set. So, when a read is explicitly initiated, all of the most recent data will come back.

But it would be nice if the new messages could appear in the MessageHistory even without you, as the user, saving your own messages. They could appear in the history even as you are in the process of writing your own content.

One way to do this would be to have the MessageApi raise an event whenever its message history data changes. Then, the AppContainer would listen for events from its MessageApi reference (which it has in its props, since props on a stateful component are used to provide references to the "external environment") as well as listening to events from the components that it renders.

On the one hand, this would actually make the save logic cleaner - the OnSave handler that the AppContainer passes to the MessageEditor in its props would only have to disable the form during the save and clear / re-enable it after the save, it wouldn't have to then request updated message data from the MessageApi, since it would know that the MessageApi would raise its own event when it had accepted the newly-saved message.

But, on the other hand, dealing with more event sources means that more logic is required in the AppContainer (which I want to move away from) and we no longer have the simple rendering-goes-down-the-tree and events-come-up-the-tree, now we have rendering-goes-down-the-tree and events-come-up-the-tree and events-come-from-some-other-places-too.

So I'm going to look at an alternative..

Extracting UI logic

Instead of the AppContainer potentially having to deal with multiple event sources and working out how events may or may not change its state, I'm going to pull that handling of UI state into another class entirely; somewhere to store this state, that will act as a single (and very simple) event source for AppContainer. This store will have a single event that the AppContainer will subscribe to; an argument-less "OnChange" event. When the AppContainer receives an "OnChange" event from the store, it will access data that the store makes available in order to update its own state reference and thus trigger a re-render.

Since events will be handled by this store, whenever an event from the component tree is passed up to the AppContainer, the AppContainer needs to pass it along to the store (instead of trying to process the event itself). So the AppContainer could act like an event source for this new store class. And, since the store class will be dealing with processing events (such as "user has requested a new message be saved"), it will also have to deal with the MessageApi being an event source.

This is a good illustration of separation of concerns - the AppContainer used to be responsible for rendering the component tree and dealing with handling events (which is where the real complexity of an application lies). With this new plan, the AppContainer will only deal with re-rendering and the event processing is dealt with by "pure" (ie. non-UI-related) C# code. However, we could still make the "multiple event source" issue a little cleaner. The store in this example will only have two event sources (the AppContainer - from user interactions - and the MessageApi - from new Chuck Norris facts arriving), but a more complex application could result in many event sources being required.

And, sometimes, a particular store might not even want access to the full event source reference; if our store was only going to be used for dealing with data for a form that edits an existing message (and doesn't want to show a message history anywhere), then it wouldn't need a full MessageApi reference - it just needs to be able to read one message in particular to edit, be able to request a change to that message be saved and then know when that save request had been processed. For this store to say that it requires a full MessageApi would be an exaggeration - it would be claiming that it had a greater dependency than it really does.

It makes sense to have one "UI store" per page of your application, so if we were to extend this example such that the main page allowed you to record new messages and see the message history and we added a way to edit a particular message on a different screen, then we might have two stores and two top-level components and a router to handle navigation from one to the other. I don't want to jump too far ahead here, I just mean to point out that different stores may rely upon different event sources and rely on different abilities of those event sources.

The message bus

So the next change that I'm going to propose is to decouple event sources from the store by having all events broadcast as messages. These are sent to some sort of message bus, which then passes them on to any interested parties. This would mean that the AppContainer would send a message to the bus whenever the user has interacted with the UI (whether this be an edit to a field or a request to save). When "SaveMessage" is called on the MessageApi then it will no longer return a Task, instead a message will be passed to the bus when the save has completed. When a new Chuck Norris fact is received by the MessageApi, it will send a message to the bus to say that new message data is available.

This would mean that the store class will only have a single "event source", which is this message bus. It will subscribe to this bus, and whenever a message is dispatched that the store is interested in then it will deal with it accordingly. If a store were to receive a message that it wasn't interested in, then it would just ignore it.

Introducing a message bus like this is a common technique to decouple areas of a system and it is another approach that makes unit testing easier later on - since the store class(es) are where the complicated event-handling logic lives, this is the code that needs the most testing. With this proposed arrangement, to test a store's logic you need only to new one up, pass it a message bus reference used solely within the current unit test, push particular messages through the bus and then verify that the store raises its OnChange event after messages when you expect it to and that the data that the store makes public is what you expect at these times. This allows all of the complicated logic to be tested with zero UI components involved and reduces the times when mocks are required since so much of the communication with the store is done via messages. (In order to test the "Save" functionality in our example app, a mock IReadAndWriteMessages would be required by our MessageWriterStore, however, so that it could call "SaveMessage" on something that doesn't actually persist data - and so that the unit test could confirm that "SaveMessage" was called with the expected data).

To summarise all of the above, we will move away slightly from the paths of communication being rendering-goes-down-the-tree and events-come-up-the-tree. Before, these paths were a continuous chain because events came up the tree and were processed and the re-render immediately went back down the tree again. Now we have rendering-goes-down-the-tree and events-come-up-the-tree but then nothing seems to happen immediately, instead the top-level component sends off a message and does nothing more.. until the store receives that message, processes it as an event (and applies any complicated logic) and then raises its OnChange event, which the top-level component receives and triggers a re-render.

I must admit, that sounds more complicated! But don't lose sight of the fact that we will side-step the complexities that multiple event sources can introduce and we will separate logic from UI, making the code more testable and making each part of it easier to reason about and thus easier to maintain and extend in the future.

(Note: This approach brings us much closer to treating everything as "asynchronous by default" - even UI changes now are implemented in a fire-and-forget manner; the top-level component sends out a message when the UI should be updated and then does nothing until it's informed by the store that it should update. While it initially feels strange to not expect to "immediately" update UI components in a synchronous manner, the advantage to async being the norm is that it's common for async code to be a bit scary in otherwise synchronous code - but here it's all the same, and not scary at all. It's also worth noting that we weren't truly updating in a synchronous manner before, since React's SetState method actually operates asynchronously - this allows React to batch updates if many occur in succession, potentially further reducing the number of times that the browser DOM actually needs to be interacted with; clever stuff!)

The new architecture

I must admit, at this point, that I can't take any credit for the above ideas. What I've outlined is referred to as the Flux Architecture (since different people have extracted their own variations on the concept, it might be safer to describe it as a Flux-like architecture, but let's not split hairs).

Below is the classic Flux diagram -

The proposed example app

The message bus is referred to as the "Dispatcher", messages are known as "Actions". The "View" is the React component tree (the AppContainer listens for the "OnChange" event from the Store and re-renders when it receives it). Note that actions come not just from the View but also from outside the cycle; in our case we have messages coming from the MessageApi when new Chuck Norris facts arrive. In an application with routing, there would be actions from the router when the URL changes.

So... what's required to get from the current architecture that the example application has to a Flux-like one?

Let's start with the Dispatcher and the messages that flow through it. The first good news is that the Bridge React bindings include a Dispatcher implementation; the AppDispatcher. This has two methods:

void Receive(Action<IDispatcherAction> callback);
void Dispatch(IDispatcherAction action);

The IDispatcherAction interface is empty and is only used as a marker to identify classes as being intended for use as a Dispatcher action.

When writing in JavaScript, actions tend to be simple objects with a "type" or "actionType" property that identifies what sort of action it is. It will then have further properties, depending upon what action it needs to describe. I've taken the below example from an article (that wasn't written by me); A (little more) complex react and flux example -

AppDispatcher.dispatch({
  actionType: BookConstants.MESSAGE_ADD,
  message: {
    color: 'green',
    text: msg
  }
});

However, we're writing in C# and we're going to take advantage of that! Our actions will be distinct types. When the store listens out messages, it won't compare an "actionType" string to work out what a particular action represents, instead we'll perform type comparisons and, when we find an action that we're interested in, we'll cast the current action to the matched type and then access its data in a type-safe manner.

Create a new folder in the project from Part One called "Actions". The simplest action to begin with is the action that would be raised by the AppContainer when the user has clicked the Save button -

using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Actions
{
  public class MessageSaveRequested : IDispatcherAction
  {
    public MessageDetails Message;
  }
}

Previously, the AppContainer's Render method contained logic about dealing with save requests -

OnSave = async () =>
{
  // Set SaveInProgress to true while the save operation is requested
  SetState(new State {
     Message = state.Message,
    IsSaveInProgress = true,
    MessageHistory = state.MessageHistory
  });
  await props.MessageApi.SaveMessage(state.Message);

  // After the save has completed, clear the message entry form and reset
  // SaveInProgress to false
  SetState(new State {
     Message = new MessageDetails { Title = "", Content = "" },
    IsSaveInProgress = false,
    MessageHistory = state.MessageHistory
  });

  // Then re-load the message history state and re-render when that data arrives
  var allMessages = await props.MessageApi.GetMessages();
  SetState(new State {
    Message = state.Message,
    IsSaveInProgress = state.IsSaveInProgress,
    MessageHistory = allMessages
  });
}

But, if all that it needs to do when a save-request bubbles up to it is send an appropriate action through the Dispatcher, then it becomes much simpler -

OnSave = () => props.Dispatcher.Dispatch(
   new MessageSaveRequested { Message = state.Message }
)

I've only shown the change to the "OnSave" property, rather than show the change within the context of the complete AppContainer class because there are other things I want to rearrange at this point. Firstly, the MessageEditor "OnChange" handler also needs to be altered - as I described above, when a user interaction is expected to require a re-render, this will not result in SetState being called immediately. Instead, an action will be sent to the Dispatcher. We need to define this action, so create another class in the "Actions" folder -

using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Actions
{
  public class MessageEditStateChanged : IDispatcherAction
  {
    public MessageEditState NewState;
  }
}

The other change is in the format of the data that is passed to the MessageEditor. Before, separate "Title", "Content" and "Disabled" values were passed to it and the component would do three things with that information -

  1. It would populate the "Title" and "Content" text inputs with the provided values
  2. If the "Title" string was populated then this value would be used to set the fieldset legend text, otherwise the legend would show "Untitled"
  3. Validation messages would be displayed for "Title" and "Content" if one or both of the values was blank

These second and third things are precisely the sort of logic that should be extracted out into the store. Consequently, the MessageEditor will be changed so that it no longer takes these individual values and, instead, takes a MessageEditState that has a "Caption" string (for the legend text), "Title" and "Content" strings and validation messages for these user-entered strings. The "Disabled" property will replaced with "IsSaveInProgress" - if this is true then none of the form elements (the text inputs or the save button) should be enabled. If a save is not in progress, then the text inputs should be enabled but the save button should only be enabled if neither validation message has any content. That is arguably more logic that could be extracted, but I think that this approach will strike a good balance - keeping the component "dumb" without having to spell out every little thing to the nth degree. Add two new files to the "ViewModels" folder to define the following classes -

namespace BridgeReactTutorial.ViewModels
{
  public class MessageEditState
  {
    public string Caption;
    public TextEditState Title;
    public TextEditState Content;
    public bool IsSaveInProgress;
  }
}

namespace BridgeReactTutorial.ViewModels
{
  public class TextEditState
  {
    public string Text;
    public string ValidationError;
  }
}

Now the MessageEditor may be rewritten to the following (note that after this change, the project isn't going to compile any more - there are a bunch of other alterations that will be required until everything builds again, all of which will be covered below):

using System;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        !string.IsNullOrWhiteSpace(props.Message.Title.ValidationError) ||
        !string.IsNullOrWhiteSpace(props.Message.Content.ValidationError);

      return DOM.FieldSet(new FieldSetAttributes { ClassName = props.ClassName },
        DOM.Legend(null, props.Message.Caption),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "title",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Title.Text,
          OnChange = newTitle => props.OnChange(new MessageEditState
          {
            Title = new TextEditState { Text = newTitle },
            Content = props.Message.Content
          }),
          ValidationMessage = props.Message.Title.ValidationError
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "content",
          Disabled = props.Message.IsSaveInProgress,
          Content = props.Message.Content.Text,
          OnChange = newContent => props.OnChange(new MessageEditState
          {
            Title = props.Message.Title,
            Content = new TextEditState { Text = newContent },
          }),
          ValidationMessage = props.Message.Content.ValidationError
        }),
        DOM.Button(
          new ButtonAttributes
          {
            Disabled = formIsInvalid || props.Message.IsSaveInProgress,
            OnClick = e => props.OnSave()
          },
          "Save"
        )
      );
    }

    public class Props
    {
      public string ClassName;
      public MessageEditState Message;
      public Action<MessageEditState> OnChange;
      public Action OnSave;
    }
  }
}

Now the AppContainer becomes much simpler -

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;
using BridgeReactTutorial.Stores;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, AppContainer.State>
  {
    public AppContainer(AppContainer.Props props) : base(props) { }

    protected override void ComponentDidMount()
    {
      props.Store.Change += StoreChanged;
    }
    protected override void ComponentWillUnmount()
    {
      props.Store.Change -= StoreChanged;
    }
    private void StoreChanged()
    {
      SetState(new State
      {
        Message = props.Store.Message,
        MessageHistory = props.Store.MessageHistory
      });
    }

    public override ReactElement Render()
    {
      if (state == null)
        return null;

      return DOM.Div(null,
        new MessageEditor(new MessageEditor.Props
        {
          ClassName = "message",
          Message = state.Message,
          OnChange = newState => props.Dispatcher.Dispatch(
            new MessageEditStateChanged { NewState = newState }
          ),
          OnSave = () => props.Dispatcher.Dispatch(
            new MessageSaveRequested
            {
              Message = new MessageDetails
              {
                Title = state.Message.Title.Text,
                Content = state.Message.Content.Text
              }
            }
          )
        }),
        new MessageHistory(new MessageHistory.Props
        {
          ClassName = "history",
          Messages = state.MessageHistory
        })
      );
    }

    public class Props
    {
      public AppDispatcher Dispatcher;
      public MessageWriterStore Store;
    }

    public class State
    {
      public MessageEditState Message;
      public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;
    }
  }
}

It is now almost devoid of logic, it only exists to listen to changes from the store (which we'll define in a moment), to render components and to direct events that are passed up from these components to the Dispatcher. Note that it no longer has any dependency upon the MessageApi.

A couple of things to note - the Dispatcher and Store are both passed to the component through its props, but when the Store raises a Change event the AppContainer copies data references from the Store into its own state, meaning that all of the information that the AppContainer requires to render itself is contained within its state. This follows the "Guidelines for Stateful Components" that I wrote last time -

  1. A stateful component's "props" data should only consist of references to external dependencies
  2. A stateful component's "state" data should include everything required to render the component tree, though the props may be required to deal with child components' events

The AppContainer now uses some React component life cycle methods that it wasn't before - "ComponentDidMount" and "ComponentWillUnmount" - to ensure that the handler attached to the Store's Change event is correctly removed when no longer required. In our example application, the AppContainer is never "unmounted" but in a more complicated application then the top-level components may be changed based upon how the user navigates through the application. (A component is "mounted" when it's being added to the component tree and "unmounted" when it's being removed - in an application with a router, the current top-level component may be changed based upon the current route, in which case there would be top-level components being mounted and unmounted as the route changes and it is important that any event handlers that they attached be detached when they're not needed).

One final thing to note before moving on to the Store implementation is that there is no longer a "GetInitialState" implementation in the AppContainer and the "Render" method will return null if state doesn't yet have a value. "GetInitialState" was another example of logic that is better placed outside of the component classes - now the AppContainer is not responsible for having to know what its initial state should be, it just renders nothing until the Store has raised a Change request that tells the AppContainer what to display.

The child components are "dumb" as all they have to do is render according to the props data that they are provided with and now the top-level stateful component is similarly "dumb" as all it does is listen to the Store and pass the information down to dumb stateless components - and then listen for events from the child components, in order to pass the information on to the Dispatcher.

We're almost ready to talk about how to create the Store now, but first we need to adapt the MessageApi to work with the Dispatcher, rather than with Tasks.

using System;
using System.Collections.Generic;
using Bridge;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    private readonly AppDispatcher _dispatcher;
    private readonly List<Tuple<int, MessageDetails>> _messages;
    public MessageApi(AppDispatcher dispatcher)
    {
      if (dispatcher == null)
        throw new ArgumentException("dispatcher");

      _dispatcher = dispatcher;
      _messages = new List<Tuple<int, MessageDetails>>();

      // To further mimic a server-based API (where other people may be recording messages
      // of their own), after a 10s delay a periodic task will be executed to retrieve a
      // new message
      Window.SetTimeout(
        () => Window.SetInterval(GetChuckNorrisFact, 5000),
        10000
      );
    }

    public RequestId SaveMessage(MessageDetails message)
    {
      return SaveMessage(message, optionalSaveCompletedCallback: null);
    }

    private RequestId SaveMessage(
      MessageDetails message,
      Action optionalSaveCompletedCallback)
    {
      if (message == null)
        throw new ArgumentNullException("message");
      if (string.IsNullOrWhiteSpace(message.Title))
        throw new ArgumentException("A title value must be provided");
      if (string.IsNullOrWhiteSpace(message.Content))
        throw new ArgumentException("A content value must be provided");

      var requestId = new RequestId();
      Window.SetTimeout(
        () =>
        {
          _messages.Add(Tuple.Create(_messages.Count, message));
          _dispatcher.Dispatch(
            new MessageSaveSucceeded { RequestId = requestId }
          );
          if (optionalSaveCompletedCallback != null)
            optionalSaveCompletedCallback();
        },
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    public RequestId GetMessages()
    {
      // ToArray is used to return a clone of the message set - otherwise, the caller would
      // end up with a list that is updated when the internal reference within this class
      // is updated (which sounds convenient but it's not the behaviour that would be
      // exhibited if this was really persisting messages to a server somewhere)
      var requestId = new RequestId();
      Window.SetTimeout(
        () => _dispatcher.Dispatch(new MessageHistoryUpdated
        {
          RequestId = requestId,
          Messages = _messages.ToArray()
        }),
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    private void GetChuckNorrisFact()
    {
      var request = new XMLHttpRequest();
      request.ResponseType = XMLHttpRequestResponseType.Json;
      request.OnReadyStateChange = () =>
      {
        if (request.ReadyState != AjaxReadyState.Done)
          return;

        if ((request.Status == 200) || (request.Status == 304))
        {
          try
          {
            var apiResponse = (ChuckNorrisFactApiResponse)request.Response;
            if ((apiResponse.Type == "success")
            && (apiResponse.Value != null)
            && !string.IsNullOrWhiteSpace(apiResponse.Value.Joke))
            {
              // The Chuck Norris Facts API (http://www.icndb.com/api/) returns strings
              // html-encoded, so they need decoding before be wrapped up in a
              // MessageDetails instance
              // - Note: After the save has been processed, GetMessages is called so
              //   that a MessageHistoryUpdate action is dispatched
              SaveMessage(
                new MessageDetails
                {
                  Title = "Fact",
                  Content = HtmlDecode(apiResponse.Value.Joke)
                },
                () => GetMessages()
              );
              return;
            }
          }
          catch
          {
            // Ignore any error and drop through to the fallback message-generator below
          }
        }
        SaveMessage(new MessageDetails
        {
          Title = "Fact",
          Content = "API call failed when polling for server content :("
        });
      };
      request.Open("GET", "http://api.icndb.com/jokes/random");
      request.Send();
    }

    private string HtmlDecode(string value)
    {
      if (value == null)
        throw new ArgumentNullException("value");

      var wrapper = Document.CreateElement("div");
      wrapper.InnerHTML = value;
      return wrapper.TextContent;
    }

    [IgnoreCast]
    private class ChuckNorrisFactApiResponse
    {
      public extern string Type { [Template("type")] get; }
      public extern FactDetails Value { [Template("value")] get; }

      [IgnoreCast]
      public class FactDetails
      {
        public extern int Id { [Template("id")] get; }
        public extern string Joke { [Template("joke")]get; }
      }
    }
  }
}

This means that the IReadAndWriteMessages interface no longer returns Tasks -

using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public interface IReadAndWriteMessages
  {
    RequestId SaveMessage(MessageDetails message);
    RequestId GetMessages();
  }
}

Each of the two methods now return a "RequestId". This is a unique identifier that will be used to tie future actions back to specific calls to the "GetMessages" or "SaveMessage" methods. When a user requests that a message be saved in our sample app, the AppContainer sends a MessageSaveRequested action through the Dispatcher. The store will receive this action from the Dispatcher and use the message data in it to call "SaveMessage", which will give the Store a unique RequestId. After the MessageApi has completed the save, it will raise a MessageSaveSucceeded action that has a "RequestId" value, the same RequestId as "SaveMessage" returned. This is how the Store knows that the save which succeeded was, in fact, the save that it initiated. In the app here, there wouldn't be any doubt since there is only one place where a new message may be saved, but in a more complicated application it's feasible that there may be multiple components that could initiate a save and it would be important to be able to be able to trace any "save succeeded" notification back to where it came from.

The RequestId has a nice feature in that two instances may be compared to determine which is most recent - this could be applicable to an application like our example because, shortly, the message history will be updated after a user has created a new message and it will be automatically updated when a new Chuck Norris fact appears. It's not too difficult to imagine that there could be a race condition that occurs when two "new message history" actions are received by the Store (one from the user-saves-message-and-then-fresh-history-is-automatically-retrieved-after-the-save-is-completed process and one from a new Chuck Norris fact arriving). In the real world, with unpredictable server and network times, it's possible for "Server Call A" to start before "Server Call B" but for "Server Call A" to finish after "Server Call B" - in this case we want the "new message history" from "Server Call B", since it should be more recent, but the data from "Server Call A" arrives after it and we need to know which result is freshest. If each action that relates to "new data arrived from API" has a RequestId then we can compare the two values using the "ComesAfter" function, allow us to ignore the stale data.

The RequestId implementation is fairly simple (add a new "RequestId.cs" file to the "API" folder and paste in the following) -

using System;

namespace BridgeReactTutorial.API
{
  public class RequestId
  {
    private static DateTime _timeOfLastId = DateTime.MinValue;
    private static int _offsetOfLastId = 0;

    private readonly DateTime _requestTime;
    private readonly int _requestOffset;
    public RequestId()
    {
      _requestTime = DateTime.Now;
      if (_timeOfLastId < _requestTime)
      {
        _offsetOfLastId = 0;
        _timeOfLastId = _requestTime;
      }
      else
        _offsetOfLastId++;
      _requestOffset = _offsetOfLastId;
    }

    public bool ComesAfter(RequestId other)
    {
      if (other == null)
        throw new ArgumentNullException("other");

      if (_requestTime == other._requestTime)
        return _requestOffset > other._requestOffset;
      return (_requestTime > other._requestTime);
    }
  }
}

In the new MessageApi code above, two actions were referenced that haven't been defined yet, so add two more classes to the "Actions" folder for the following:

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Actions
{
  public class MessageHistoryUpdated : IDispatcherAction
  {
    public RequestId RequestId;
    public IEnumerable<Tuple<int, MessageDetails>> Messages;
  }
}

using Bridge.React;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Actions
{
  public class MessageSaveSucceeded : IDispatcherAction
  {
    public RequestId RequestId;
  }
}

(Note: A MessageHistoryUpdated will be emitted after a "GetMessages" call is made but one will also be emitted every time that a new Chuck Norris fact arrives).

While we're adding actions, we're going to need a StoreInitialised action class (I'll talk about this more later on, for now just add the following class to the "Actions" folder):

using Bridge.React;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Actions
{
  public class StoreInitialised : IDispatcherAction
  {
    public object Store;
  }
}

Now, finally, we so create a Store.

Create a new folder in the project root called "Stores" and add a new class file to it; "MessageWriterStore.cs" -

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Stores
{
  public class MessageWriterStore
  {
    private RequestId _saveActionRequestId, _lastDataUpdatedRequestId;
    public MessageWriterStore(IReadAndWriteMessages messageApi, AppDispatcher dispatcher)
    {
      if (messageApi == null)
        throw new ArgumentNullException("messageApi");
      if (dispatcher == null)
        throw new ArgumentNullException("dispatcher");

      Message = GetInitialMessageEditState();
      MessageHistory = new Tuple<int, MessageDetails>[0];

      dispatcher.Receive(action =>
      {
        if (action is StoreInitialised)
        {
          var storeInitialised = (StoreInitialised)action;
          if (storeInitialised.Store == this)
            OnChange();
        }
        else if (action is MessageEditStateChanged)
        {
          var messageEditStateChanged = (MessageEditStateChanged)action;
          Message = messageEditStateChanged.NewState;
          ValidateMessage(Message);
          OnChange();
        }
        else if (action is MessageSaveRequested)
        {
          var messageSaveRequested = (MessageSaveRequested)action;
          _saveActionRequestId = messageApi.SaveMessage(messageSaveRequested.Message);
          Message.IsSaveInProgress = true;
          OnChange();
        }
        else if (action is MessageSaveSucceeded)
        {
          var messageSaveSucceeded = (MessageSaveSucceeded)action;
          if (messageSaveSucceeded.RequestId == _saveActionRequestId)
          {
            _saveActionRequestId = null;
            Message = GetInitialMessageEditState();
            OnChange();
            _lastDataUpdatedRequestId = messageApi.GetMessages();
          }
        }
        else if (action is MessageHistoryUpdated)
        {
          var messageHistoryUpdated = (MessageHistoryUpdated)action;
          if ((_lastDataUpdatedRequestId == null)
          || (_lastDataUpdatedRequestId == messageHistoryUpdated.RequestId)
          || messageHistoryUpdated.RequestId.ComesAfter(_lastDataUpdatedRequestId))
          {
            _lastDataUpdatedRequestId = messageHistoryUpdated.RequestId;
            MessageHistory = messageHistoryUpdated.Messages;
            OnChange();
          }
        }
      });
    }

    public event Action Change;
    public MessageEditState Message;
    public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;

    private MessageEditState GetInitialMessageEditState()
    {
      // Note: By using the ValidateMessage here, we don't need to duplicate the "Untitled"
      // string that should be used for the Caption value when the UI is first rendered
      // or when the user has entered some Title content but then deleted it again.
      // Similarly, we avoid having to repeat the validation messages that should be
      // displayed when the form is empty, since they will be set by ValidateMessage.
      var blankMessage = new MessageEditState
      {
        Caption = "",
        Title = new TextEditState { Text = "" },
        Content = new TextEditState { Text = "" },
        IsSaveInProgress = false
      };
      ValidateMessage(blankMessage);
      return blankMessage;
    }

    private void ValidateMessage(MessageEditState message)
    {
      if (message == null)
        throw new ArgumentNullException("message");

      message.Caption = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Untitled"
        : message.Title.Text.Trim();
      message.Title.ValidationError = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Must enter a title"
        : null;
      message.Content.ValidationError = string.IsNullOrWhiteSpace(message.Content.Text)
        ? "Must enter message content"
        : null;
    }

    private void OnChange()
    {
      if (Change != null)
        Change();
    }
  }
}

There's really nothing very complicated here at all. What I like is that all of the logic that was previously ensconced within component classes is now in a C# class which has zero UI-based dependencies. What I also like is how clear the logic is, it's very easy to read through how the various actions are matched and to see precisely what state changes will occur. In fact, the MessageWriterStore is just a simple state machine where each transition is based upon the action that it receives from the Dispatcher. It's reassuring that the Flux architecture is based upon these time-tested computer science devices; the message bus and state machine - while it might take a little while to internalise how to write applications based around this "one-way binding" / "one-way message passing" arrangement, once it clicks it feels very natural.

Having the core application logic in classes like this really helps ensure that code will have those two great properties that I will keep repeating through this series - that it's easy to reason about and that it's easy to test. It's easy to reason about as it's easy to see how user (and server) actions flow through the code, there are few surprises. It's easy to test because there are few dependencies - to test anything in the MessageWriterStore, each unit test would need to provide an AppDispatcher instance and a mock IReadAndWriteMessages implementation, it would then push one or more messages through the Dispatcher and confirm that the public MessageWriterStore state matches expectations at the end. For example, to test the "Content" text input validation, you would play back a MessageEditStateChanged action with a blank "Content" string in the MessageEditState and ensure that the expected validation message text was present in the "Message" reference of the MessageWriterStore afterwards.

There are a couple of minor things that I'm not so keen about in the code above. Firstly, there's the laborious type-checking and casting that is required when matching the actions. Secondly, there's the duplication on calling "OnChange" whenever an action is matched. Thirdly, the logic around RequestId comparison when a MessageHistoryUpdated is matched is a bit clumsy.

For that third point, add a new file "RequestIdExtensions.cs" to the "API" folder with the following content -

using System;

namespace BridgeReactTutorial.API
{
  public static class RequestIdExtensions
  {
    public static bool IsEqualToOrComesAfter(this RequestId source, RequestId other)
    {
      if (source == null)
        throw new ArgumentNullException("source");

      // If the "other" reference is no-RequestId then the "source" may be considered to
      // come after it
      if (other == null)
        return true;

      return (source == other) || source.ComesAfter(other);
    }
  }
}

And for the first two points, we can use some extension methods which are included in the Bridge / React bindings -

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Stores
{
  public class MessageWriterStore
  {
    private RequestId _saveActionRequestId, _lastDataUpdatedRequestId;
    public MessageWriterStore(IReadAndWriteMessages messageApi, AppDispatcher dispatcher)
    {
      if (messageApi == null)
        throw new ArgumentNullException("messageApi");
      if (dispatcher == null)
        throw new ArgumentNullException("dispatcher");

      Message = GetInitialMessageEditState();
      MessageHistory = new Tuple<int, MessageDetails>[0];

      dispatcher.Receive(a => a
        .If<StoreInitialised>(
          condition: action => (action.Store == this),
          work: action => { }
        )
        .Else<MessageEditStateChanged>(action =>
        {
          Message = action.NewState;
          ValidateMessage(Message);
        })
        .Else<MessageSaveRequested>(action =>
        {
          _saveActionRequestId = messageApi.SaveMessage(action.Message);
          Message.IsSaveInProgress = true;
        })
        .Else<MessageSaveSucceeded>(
          condition: action => (action.RequestId == _saveActionRequestId),
          work: action =>
          {
            _saveActionRequestId = null;
            Message = GetInitialMessageEditState();
            _lastDataUpdatedRequestId = messageApi.GetMessages();
          }
        )
        .Else<MessageHistoryUpdated>(
          condition: action =>
            action.RequestId.IsEqualToOrComesAfter(_lastDataUpdatedRequestId),
          work: action =>
          {
            _lastDataUpdatedRequestId = action.RequestId;
            MessageHistory = action.Messages;
          }
        )
        .IfAnyMatched(OnChange)
      );
    }

    public event Action Change;
    public MessageEditState Message;
    public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;

    private MessageEditState GetInitialMessageEditState()
    {
      // Note: By using the ValidateMessage here, we don't need to duplicate the "Untitled"
      // string that should be used for the Caption value when the UI is first rendered
      // or when the user has entered some Title content but then deleted it again.
      // Similarly, we avoid having to repeat the validation messages that should be
      // displayed when the form is empty, since they will be set by ValidateMessage.
      var blankMessage = new MessageEditState
      {
        Caption = "",
        Title = new TextEditState { Text = "" },
        Content = new TextEditState { Text = "" },
        IsSaveInProgress = false
      };
      ValidateMessage(blankMessage);
      return blankMessage;
    }

    private void ValidateMessage(MessageEditState message)
    {
      if (message == null)
        throw new ArgumentNullException("message");

      message.Caption = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Untitled"
        : message.Title.Text.Trim();
      message.Title.ValidationError = string.IsNullOrWhiteSpace(message.Title.Text)
        ? "Must enter a title"
        : null;
      message.Content.ValidationError = string.IsNullOrWhiteSpace(message.Content.Text)
        ? "Must enter message content"
        : null;
    }

    private void OnChange()
    {
      if (Change != null)
        Change();
    }
  }
}

Hopefully it's clear enough how they work. The "If" and the "Else" functions both have a generic type parameter for the kind of action to match and may be called with a single "work" argument (meaning "do this if the action type is matched") or two arguments; "condition" and "work" (where "condition" looks at the action, typed to match the generic type parameter, and returns true or false depending upon whether the action should be considered or ignored). The "condition" argument is most clearly illustrated by the MessageHistoryUpdated, it ensures that any stale MessageHistoryUpdated action will be ignored. The "work" implementation for StoreInitialised is empty because all that is required when a StoreInitialised action is received (that targets the current store) is to call "OnChange" and the "IfAnyMatched" extension method calls "OnChange" if any of the actions are matched.

There's just one final thing to do now in order to make the application compile again, the entry point logic in App.cs needs updating -

using System.Linq;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.API;
using BridgeReactTutorial.Components;
using BridgeReactTutorial.Stores;

namespace BridgeReactTutorial
{
  public class App
  {
    [Ready]
    public static void Go()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );

      var dispatcher = new AppDispatcher();
      var messageApi = new MessageApi(dispatcher);
      var store = new MessageWriterStore(messageApi, dispatcher);
      React.Render(
        new AppContainer(new AppContainer.Props
        {
          Dispatcher = dispatcher,
          Store = store
        }),
        container
      );
      dispatcher.Dispatch(new StoreInitialised { Store = store });
    }
  }
}

Both the MessageWriterStore and the AppContainer need a reference to a shared Dispatcher, MessageWriterStore needs a Message API wrapper to talk to and the AppContainer needs a reference to the Store. In a lot of the Flux articles that I read at first, the Dispatcher was a static reference that everything had access to - but I much prefer this arrangement, where the places that explicitly need it (ie. the Stores and the top-level components) have it passed in as a constructor argument or through props. This makes a class' requirements much more explicit - if a class has implicit dependencies then it's more difficult to tell at a glance how it works. And not having a static Dispatcher means that unit testing is simpler, since there is no implicit shared state between elements within an application.

The only part of this code that may not be very intuitive is the need to send a StoreInitialised action to the Dispatcher immediately after setting up all of the references. This is required before the AppContainer won't render anything until it processes its first "Change" event from the MessageWriterStore (because, until that point, the AppContainer's state reference will be null). When the Store receives the StoreInitialised action, it will raise its "Change" event and the AppContainer will perform its first "real" render. If this was an application with a routing element, with a Store per page / form, then it would seem natural for the router to raise a StoreInitialised action for the Store that should be active for the current route (it is just a little odd-looking in a simple application like the example here unless you know why it is necessary).

Lots of actions?

With that, the change in architecture is complete. Hopefully it's easy to envisage how further functionality is enabled by adding further specialised components and communicating using different action types. Each action is handled in a very clear way in the Store(s) and so the overall complexity should (approximately) grow linearly with the essential complexity, rather than exponentially (which is what tends to happens a lot with more haphazard architectures, or where you have the "star-shaped event handling" that I described earlier).

The only adjustment that I'd like to make at this point is to the actions themselves - if there's a variation of the MessageEditStateChanged, MessageSaveRequested and MessageSaveSucceeded actions required for every kind of form where a user creates / edits data and tries to save it, then there's going to be a lot of action classes that are basically the same.

This seems like a perfect case for C# generics - a single generic class may be used to represent many types of user edit action without sacrificing type safety. Rename the "MessageEditStateChanged.cs" action class to "UserEditRequested.cs" and replace the content, which is currently:

using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Actions
{
  public class MessageEditStateChanged : IDispatcherAction
  {
    public MessageEditState NewState;
  }
}

With this:

using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Actions
{
  public class UserEditRequested<T> : IDispatcherAction
  {
    public T NewState;
  }
  public static class UserEditRequested
  {
    public static UserEditRequested<T> For<T>(T newState)
    {
      return new UserEditRequested<T> { NewState = newState };
    }
  }
}

Now, anywhere that there is a reference to MessageEditStateChanged, you will need to change it to be a UserEditRequested<MessageEditState>.

The non-generic "For" function is just for convenience, it allows you to create a new UserEditRequested<T> instance without writing out the type of "T" - it will be inferred by the type of the "newState" reference passed for it. The "OnChange" lambda set on the MessageEditor props was previously

OnChange = newState => props.Dispatcher.Dispatch(
  new MessageEditStateChanged { NewState = newState }
)

but should now become

OnChange = newState => props.Dispatcher.Dispatch(
  UserEditRequested.For(newState)
)

(Since "newState" is a MessageEditState instance, the action that will be raised will be a UserEditRequested<MessageEditState>).

Now, the action-matching code in the MessageWriteStore needs to change from

.Else<MessageEditStateChanged>(action =>
{
  Message = action.NewState;
  ValidateMessage(Message);
})

to

.Else<UserEditRequested<MessageEditState>>(action =>
{
  Message = action.NewState;
  ValidateMessage(Message);
})

Similar changes should be made, so that "MessageSaveRequested.cs" is replaced with

using Bridge.React;

namespace BridgeReactTutorial.Actions
{
  public class SaveRequested<T> : IDispatcherAction
  {
    public T Data;
  }
  public static class SaveRequested
  {
    public static SaveRequested<T> For<T>(T data)
    {
      return new SaveRequested<T> { Data = data };
    }
  }
}

And "MessageSaveSucceeded.cs" is replaced with

using Bridge.React;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Actions
{
  public class SaveSucceeded : IDispatcherAction
  {
    public RequestId RequestId;
  }
}

And, finally, "MessageHistoryUpdated.cs" replaced with

using Bridge.React;
using BridgeReactTutorial.API;

namespace BridgeReactTutorial.Actions
{
  public class DataUpdated<T> : IDispatcherAction
  {
    public RequestId RequestId;
    public T Data;
  }
  public static class DataUpdated
  {
    public static DataUpdated<T> For<T>(RequestId requestId, T data)
    {
      return new DataUpdated<T> { RequestId = requestId, Data = data };
    }
  }
}

(Note that SaveSucceeded is not a generic class because the only information that it contains is the RequestId that corresponds to the save operation that it indicates has completed).

The action type-matching that occurs in the MessageWriteStore now needs to be changed to:

dispatcher.Receive(a => a
  .If<StoreInitialised>(
    condition: action => (action.Store == this),
    work: action => { }
  )
  .Else<UserEditRequested<MessageEditState>>(action =>
  {
    Message = action.NewState;
    ValidateMessage(Message);
  })
  .Else<SaveRequested<MessageDetails>>(action =>
  {
    _saveActionRequestId = messageApi.SaveMessage(action.Data);
    Message.IsSaveInProgress = true;
  })
  .Else<SaveSucceeded>(
    condition: action => (action.RequestId == _saveActionRequestId),
    work: action =>
    {
      _saveActionRequestId = null;
      Message = GetInitialMessageEditState();
      _lastDataUpdatedRequestId = messageApi.GetMessages();
    }
  )
  .Else<DataUpdated<IEnumerable<Tuple<int, MessageDetails>>>>(
    condition: action =>
      action.RequestId.IsEqualToOrComesAfter(_lastDataUpdatedRequestId),
    work: action =>
    {
      _lastDataUpdatedRequestId = action.RequestId;
      MessageHistory = action.Data;
    }
  )
  .IfAnyMatched(OnChange)
);

The AppContainer now becomes:

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;
using BridgeReactTutorial.Stores;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, AppContainer.State>
  {
    public AppContainer(AppContainer.Props props) : base(props) { }

    protected override void ComponentDidMount()
    {
      props.Store.Change += StoreChanged;
    }
    protected override void ComponentWillUnmount()
    {
      props.Store.Change -= StoreChanged;
    }
    private void StoreChanged()
    {
      SetState(new State
      {
        Message = props.Store.Message,
        MessageHistory = props.Store.MessageHistory
      });
    }

    public override ReactElement Render()
    {
      if (state == null)
        return null;

      return DOM.Div(null,
        new MessageEditor(new MessageEditor.Props
        {
          ClassName = "message",
          Message = state.Message,
          OnChange = newState => props.Dispatcher.Dispatch(
            UserEditRequested.For(newState)
          ),
          OnSave = () => props.Dispatcher.Dispatch(
            SaveRequested.For(new MessageDetails
            {
              Title = state.Message.Title.Text,
              Content = state.Message.Content.Text
            })
          )
        }),
        new MessageHistory(new MessageHistory.Props
        {
          ClassName = "history",
          Messages = state.MessageHistory
        })
      );
    }

    public class Props
    {
      public AppDispatcher Dispatcher;
      public MessageWriterStore Store;
    }

    public class State
    {
      public MessageEditState Message;
      public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;
    }
  }
}

And the MessageApi:

using System;
using System.Collections.Generic;
using System.Linq;
using Bridge;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Actions;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    private readonly AppDispatcher _dispatcher;
    private readonly List<Tuple<int, MessageDetails>> _messages;
    public MessageApi(AppDispatcher dispatcher)
    {
      if (dispatcher == null)
        throw new ArgumentException("dispatcher");

      _dispatcher = dispatcher;
      _messages = new List<Tuple<int, MessageDetails>>();

      // To further mimic a server-based API (where other people may be recording messages
      // of their own), after a 10s delay a periodic task will be executed to retrieve a
      // new message
      Window.SetTimeout(
        () => Window.SetInterval(GetChuckNorrisFact, 5000),
        10000
      );
    }

    public RequestId SaveMessage(MessageDetails message)
    {
      return SaveMessage(message, optionalSaveCompletedCallback: null);
    }

    private RequestId SaveMessage(MessageDetails message, Action optionalSaveCompletedCallback)
    {
      if (message == null)
        throw new ArgumentNullException("message");
      if (string.IsNullOrWhiteSpace(message.Title))
        throw new ArgumentException("A title value must be provided");
      if (string.IsNullOrWhiteSpace(message.Content))
        throw new ArgumentException("A content value must be provided");

      var requestId = new RequestId();
      Window.SetTimeout(
        () =>
        {
          _messages.Add(Tuple.Create(_messages.Count, message));
          _dispatcher.Dispatch(new SaveSucceeded { RequestId = requestId });
          if (optionalSaveCompletedCallback != null)
            optionalSaveCompletedCallback();
        },
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    public RequestId GetMessages()
    {
      // ToArray is used to return a clone of the message set - otherwise, the caller would
      // end up with a list that is updated when the internal reference within this class
      // is updated (which sounds convenient but it's not the behaviour that would be
      // exhibited if this was really persisting messages to a server somewhere).. and
      // then AsEnumerable() is required since the store checks for an action of type
      // DataUpdated<IEnumerable<Tuple<int, MessageDetails>>>>
      var requestId = new RequestId();
      Window.SetTimeout(
        () => _dispatcher.Dispatch(DataUpdated.For(requestId, _messages.ToArray().AsEnumerable())),
        1000 // Simulate a roundtrip to the server
      );
      return requestId;
    }

    private void GetChuckNorrisFact()
    {
      var request = new XMLHttpRequest();
      request.ResponseType = XMLHttpRequestResponseType.Json;
      request.OnReadyStateChange = () =>
      {
        if (request.ReadyState != AjaxReadyState.Done)
          return;

        if ((request.Status == 200) || (request.Status == 304))
        {
          try
          {
            var apiResponse = (ChuckNorrisFactApiResponse)request.Response;
            if ((apiResponse.Type == "success")
            && (apiResponse.Value != null)
            && !string.IsNullOrWhiteSpace(apiResponse.Value.Joke))
            {
              // The Chuck Norris Facts API (http://www.icndb.com/api/) returns strings
              // html-encoded, so they need decoding before be wrapped up in a
              // MessageDetails instance
              // - Note: After the save has been processed, GetMessages is called so
              //   that a MessageHistoryUpdate action is dispatched
              SaveMessage(
                new MessageDetails
                {
                  Title = "Fact",
                  Content = HtmlDecode(apiResponse.Value.Joke)
                },
                () => GetMessages()
              );
              return;
            }
          }
          catch
          {
            // Ignore any error and drop through to the fallback message-generator below
          }
        }
        SaveMessage(new MessageDetails
        {
          Title = "Fact",
          Content = "API call failed when polling for server content :("
        });
      };
      request.Open("GET", "http://api.icndb.com/jokes/random");
      request.Send();
    }

    private string HtmlDecode(string value)
    {
      if (value == null)
        throw new ArgumentNullException("value");

      var wrapper = Document.CreateElement("div");
      wrapper.InnerHTML = value;
      return wrapper.TextContent;
    }

    [IgnoreCast]
    private class ChuckNorrisFactApiResponse
    {
      public extern string Type { [Template("type")] get; }
      public extern FactDetails Value { [Template("value")] get; }

      [IgnoreCast]
      public class FactDetails
      {
        public extern int Id { [Template("id")] get; }
        public extern string Joke { [Template("joke")]get; }
      }
    }
  }
}

(I contemplated leaving it as an exercise for the reader to change all of the action instantiation code to use the new generic classes, but with so much code in this post already I thought I might as well go whole-hog and include the final version of the everything!)

No type-safety has been lost in this refactor but, hopefully, it's clear how action classes can scale with an application's complexity. Needing a lot of new actions every time that a new section is added to an application would be no fun and would just add to the code churn required, so being able to reuse actions like this is a boon.

The third and final part

We've covered a lot of ground here, so I'm going to draw things to a close. Flux is a big deal and I've read plenty of articles that make it sound mind-bending and difficult to grasp. Hopefully this has explored why it makes sense as much as how to think in terms of it (and write code in the style of it!).

Next time, now that React and Flux are dealt with, I want to look at how we can go further in the quest to make code easier to reason about and to test - there is a lot more that we can do with the C# type system to really express intent, requirements and limitations and I strongly believe that doing so will lead to higher quality code. As a side benefit, I'll also be showing how to make a simple tweak to components that will offer potentially huge performance benefits to highly-complex / deeply-nested UIs. I really think that using C# and Bridge can be more than just a possibility for writing React applications, it can be one of the best ways to do so!

Posted at 22:50

Comments

Writing React apps using Bridge.NET - The Dan Way (from first principles)

(This is part one of a three part series, each post is longer than the last so strap yourself in if you're thinking of playing along - hopefully you'll think that it was worth it by the end! :)

I've had a request from someone to write about how I think that someone from a .net background should write a web-based application. The short answer is that I strongly believe that using Bridge.NET with React, using a Flux-like architecture is the way forward. I think that React changed the game by trying to introduce a way to write applications that addressed the big challenges, rather than what many of the other frameworks did, which was to try to make some aspects of development easier but without tackling the underlying problems. We're going to be using these technologies to create some big applications where I work and some resources as to how best to do this will be valuable. I'm going to try to roll this all together into a short series of posts about creating Bridge / React / Flux apps, where I'll try to start from the simplest approach at each point and only introduce something new when I can explain why it's valuable. So, initially, Flux will be nowhere to be seen - but, hopefully, when it is introduced, it will be clear why.

(I'm not going to expel any effort on convincing you that writing C# in Visual Studio is incredibly powerful, and that it's fantastic to be able to do this while writing browser-based applications, nor am I going to try to sell you any more on React - if you're not on board with these ideas already then there's a chance that these posts will sell you on it, but that's not going to be my main focus).

From the very start

I'm going to begin from a completely fresh project, so if you've got any experience with Bridge then these steps will be familiar. But I'll go through them quickly and then start building the application itself. It's going to be extremely simple but will illustrate how to work with React and how to deal with user input and Virtual DOM re-rendering, how and where to implement validation and how to make all the things asynchronous so that async is not only used for scary edge cases and can be seen as a valuable tool to decouple code (and, in doing so, async will become a not-at-all-scary thing).

All that the application will do will be to allow the user to write a message, entering Title and Content strings, and to save this message. There will be a "Message API", which will emulate reading and writing to a remote endpoint, for data persistence, but the implementation will all be kept in-memory / in the browser, just to make things simple. It will look something like this:

The proposed example app

As more messages are written, more entries will appear in the "Message History". Seems simple.

React components

Before getting into any React-with-Bridge specifics, I want to talk a little about React components; how to arrange them into a hierarchy and how they should and shouldn't talk to each other.

Almost all of the time, components that you use will be "controlled components" -

A Controlled component does not maintain its own internal state; the component renders purely based on props.

This means that when you render a text input, you give it a "value" property and an "onChange" property - when the user tries to change what's in the text box (whether by pressing a number or letter, or by pressing backspace or by pasting something in) then the "onChange" callback is executed. The text box is not updated automatically, all that happens is that a callback is made that indicates that the user has done something that means that the text input probably should be updated.

This seems odd at the very start since you may be used to events being driven by html elements and the updates being broadcast elsewhere; with React, events arise from components that describe the desire for a change to be made, but the change does not happen automatically. This is what is meant in the quote above when it says that a controlled component "does not maintain its own internal state".

This hints at one of the key aims of React - to make code explicit and easy to reason about. If a component only varies based upon its props, then it's very easy to reason about; given this props data, draw in this manner. (If user-entered changes to a text input were automatically reflected in the text box then the component would not solely vary by its props, it would vary according to its props and whatever else the user has done to it).

The only way for a component to update / re-render itself (and any child components that it may have) is for it to changes its "state". This is a special concept in React - if "SetState" is called then the component will re-render, but now it may have to consider both its props and its new state. If we really wanted to have a text input that would automatically update its own value as well as raise a change event, we could write a component to do so -

(Note: if you're coming into this fresh, don't worry about how to compile this C# code into a React application, I'll be getting to that after I've finished giving my view on React components).

public class TextInput : Component<TextInput.Props, TextInput.State>
{
  public TextInput(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Input(new InputAttributes
    {
      Type = InputType.Text,
      Value = (state == null) ? props.InitialValue : state.Value,
      OnChange = ev =>
      {
        var newValue = ev.CurrentTarget.Value;
        SetState(new State { Value = newValue });
        props.OnChange(newValue);
      }
    });
  }

  public class Props
  {
    public string InitialValue;
    public Action<string> OnChange;
  }

  public class State
  {
    public string Value;
  }
}

The problem here is that now the component depends upon two things whenever it has to render - its props and its state. It can change its own state but it can't change its props (React demands that a components props be considered to be immutable).

This means that the component becomes more difficult to reason about, it was much easier when it didn't have to worry about state. (Granted, there may have been some question as to who would receive that OnChange callback to get the component to re-render, but we're going to get to that shortly).

Partly for this reason, it's strongly recommended that the vast majority of components be stateless - meaning that they render according to their props and nothing else.

Another reason that it is strongly recommended that components not update themselves (meaning that they are stateless, since the only way for a component to update itself is to change its state) is that it makes the handling of events much clearer. In the example application that I'm going to refer to in this series, the "Title" value that is entered by the user is reflected in the fieldset legend -

Fieldset legend mirrors the Title input value

If the "Title" input box was to maintain its own state and update itself when its contents change, there still needs to be something listening for changes in order to update the fieldset legend text. If it was common for components to maintain their own state then things would quickly get out of hand as more and more components have to listen for (and react to) changes in other components. Just in the example here, there is a validation message that needs to be hidden if the "Title" input has a non-blank value, so that component would need to listen for the change event on the input. (Alternatively, the TextInput component could be provided with validation logic and it would be responsible for showing or hiding the validation message - which would complicate the TextInput class). On top of this, there is the "Save" button which should be disabled if either of the "Title" or "Content" input boxes have no value - so the Save button component would need to listen to change events from both text inputs and decide whether or not it should be enabled based upon their states. Maybe the input form itself wants to add an "invalid" class to itself for styling purposes if either of the inputs are invalid - now the form component has to listen to changes to the text inputs and add or remove this class. This way lies madness.

In summary, most components should not try to update themselves and so do not need state. The React bindings make it easy to write components that don't use state (again, I'll talk about using these bindings more shortly, I just wanted to point out now that the distinction between stateful and stateless components is an important one and that the bindings reflect this) -

public class TextInput : StatelessComponent<TextInput.Props>
{
  public TextInput(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Input(new InputAttributes
    {
      Type = InputType.Text,
      Value = props.Value,
      OnChange = ev => props.OnChange(ev.CurrentTarget.Value)
    });
  }

  public class Props
  {
    public string Value;
    public Action<string> OnChange;
  }
}

The component code is much more succinct this way, as well as helping us avoid the nightmare scenario described above.

It does leave one big question, though.. if these components don't update themselves, then what does?

Answer: There should be a top-level "Container Component" that maintains state for the application. This should be the only stateful component, all components further down the hierarchy should be stateless.

In the sample application here -

The proposed example app

The component hierarchy will look something like this:

AppContainer
  MessageEditor
    Span ("Title")
    ValidatedTextInput
      Input
    Span ("Content")
    ValidatedTextInput
      Input
    Button
  MessageHistory
    Div
      Span (Message Title)
      Span (Message Content)
    Div
      Span (Message Title)
      Span (Message Content)

The MessageHistory will be a read-only component tree (it just shows saved messages) and so is very simple (there are no callbacks to handle). The MessageEditor will render Span labels ("Title" and "Content"), two ValidatedTextInput components and a "Save" button. The ValidatedTextInput has props for a current text input value, an on-change callback and an optional validation message.

When an input component's on-change callback is executed, it is an action with a single argument; the html element. In the TextInput example class above, the new value is extracted from that element ("ev.CurrentTarget.Value") and then passed into the on-change callback of the TextInput, which is an action with a simple string argument. ValidatedTextInput will be very similar (it will wrap the Action<InputElement> callback that the input raises in a simpler Action<string>). The only difference between it and the TextInput example class earlier is that it will also be responsible for rendering a validation message element if its props value has a non-blank validation message to show (and it may apply an "invalid" class name to its wrapper if there is a validation message to show).

When the Title or Content ValidatedTextInput raise an on-change event, the MessageEditor will execute some code that translates this callback further. The MessageEditor will have an on-change props value whose single argument is a MessageDetails - this will have have values for the current "Title" and "Content". Just as an on-change from an input element resulted in an on-change being raised by a ValidatedTextInput, an on-change by a ValidatedTextInput will result in an on-change from the MessageEditor. Each on-change event changes the type of value that the on-change describes (from an input element to a string to a MessageDetails). The MessageEditor's on-change will be received by the AppContainer Component, which is where the change will result in the component tree being re-rendered.

The AppContainer component will re-render by calling "SetState" and creating a new state reference for itself that include the new MessageDetails reference (that was passed up in the on-change callback from the MessageEditor). The call to "SetState" will result in the component being re-rendered, which will result in it rendering a new version of the MessageEditor. When the MessageEditor is rendered, the current "Title" value will be used to populate the text input and to set the text in the legend of the fieldset that wraps the editor's input boxes. This is how the "nightmare scenario" described earlier is avoided - instead of having lots of components listen out to events from lots of other components, all components just pass their events up to the top and then the entire UI is re-rendered in React's Virtual DOM.

I'm going to repeat that part about event-handling because it's important; events are passed up from where they occur, up to the top-level component. This will trigger a re-render, which works all the way down through the component tree, so that the requested change is then reflected in the UI.

The Virtual DOM determines what (if anything) needs to change in the browser's DOM and applies those changes - this works well because the Virtual DOM is very fast (and so we can do these "full Virtual DOM re-renders" frequently) and it minimises changes to the browser DOM (which is much slower).

(The Facebook tutorial Thinking in React talks about how to mentally break down a UI into components and talks about passing state up the tree, but I wanted to try to really drive home how components should be put together and how they should communicate before fobbing you off with a Facebook link).

I have some more recommendations on how to decide what to put into props and what into state when creating stateful container components, but I'll cover that ground after some more practical work.

Let's start coding then!

Open up Visual Studio (the version isn't too important, but if you're using 2015 then bear in mind that Bridge.NET doesn't yet support C# 6 syntax). Create a new "Class Library" project. Using NuGet, add the "Bridge" and the "Bridge.React" packages. This will bring in bindings for React as well as pulling in Bridge itself - the Bridge package removes the usual System, System.Collections, etc.. references and replaces them with a single "Bridge" reference, which re-implements those framework methods in code that has JavaScript translations.

The Bridge package also adds some README files and a bridge.json file (under the Bridge folder in the project), which instructs Bridge how to compile your C# code into JavaScript. Change bridge.json's content to:

{
  "output": "Bridge/output",
  "combineScripts":  true
}

This will tell it create a single JavaScript file when translating, including the Bridge library content and the React bindings and JavaScript generated from code that you write. The name of the file that it generates is based upon the name of your project. I named mine "BridgeReactTutorial" and so the Bridge compiler will generate "BridgeReactTutorial.js" and "BridgeReactTutorial.min.js" files in the "Bridge/output" folder on each build of the project.

Now create an empty html file in the project root called "demo.html" and paste in the following:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta charset="utf-8" />
  <title>Bridge.React Tutorial</title>
  <link rel="Stylesheet" type="text/css" href="styles.css" media="screen" />
</head>
<body>
  <noscript>JavaScript is required</noscript>
  <div id="main" class="loading">Loading..</div>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.7/react-dom.js"></script>
  <script src="Bridge/output/BridgeReactTutorial.js"></script>
</body>
</html>

(If you called your project something other than "BridgeReactTutorial" then you might have to change the filename in that last script tag).

This file will load in the latest (0.14.7, as of March 2016) version of the React library along with the Bridge / React-bindings / your-code bundle. All we need to do now is write some "your-code" content.

When you created the class library project, a Class1.cs file will have been added to the project. Change its contents -

using System.Linq;
using Bridge.Html5;
using Bridge.React;

namespace BridgeReactTutorial
{
  public class Class1
  {
    [Ready]
    public static void Main()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );
      React.Render(
        DOM.Div(new Attributes { ClassName = "welcome" }, "Hi!"),
        container
      );
    }
  }
}

Build the solution and then right-click on the "demo.html" file in the project and click on "View in Browser". You should see a happy little "Hi!" welcome message, rendered using React by JavaScript that was translated from C# - an excellent start!

There are some subtle touches here, such as the "JavaScript is required" message that is displayed if the browser has JavaScript disabled (just in case you ever turn it off and forget!) and a "loading" message that is displayed while the JavaScript sorts itself out (usually this will be a barely-perceptible amount of time but if the CDN host that the React library is coming from is being slow then it may not be instantaneous). The "main" div initially has a "loading" class on it, which is removed when the code above executes. Note that the [Ready] attribute on the "Main" function is a Bridge attribute, indicating code that should be called when the page has loaded (similar in principle to on-DOM-ready, frequently used by jQuery code).

To take advantage of the "loading" class' presence / absence, it would be a nice touch to have the "loading" text quite pale initially (it's reassuring to know that the app is, in fact, loading, but it doesn't need to be right in your face). To do so, add a file "styles.css" alongside the "demo.html" file. It's already referenced by the markup we've pasted into "demo.html", so it will be picked up when you refresh the page. Since we're creating a stylesheet, it makes sense to include some style resets (my go-to for this is by Eric Meyer) -

/* http://meyerweb.com/eric/tools/css/reset/ v2.0b1 | 201101 NOTE: WORK IN PROGRESS
 USE WITH CAUTION AND TEST WITH ABANDON */
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote,
pre,a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s,
samp, small, strike, strong, sub, sup, tt, var,b, u, i, center, dl, dt, dd, ol, ul,
li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu,
nav, section, summary, time, mark, audio, video
{
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav,
section { display: block; }
body { line-height: 1; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
/* remember to highlight inserts somehow! */ ins { text-decoration: none; }
del { text-decoration: line-through; }
table { border-collapse: collapse; border-spacing: 0; }

div#main.loading { color: #f1f1f1; }

At this point, I also tend to remove the "App_Readme" folder that the Bridge package adds to my project - if I'm going to write some code and check it into source control somewhere then I don't think there's a lot of point in storing a copy of the Bridge README and LICENSE each time.

Creating the Message Editor

That's the theory and the project scaffolding out of the way. Now to create a form that actually does something.

We've already seen how a TextInput component is helpful for wrapping a text input and simplifying the "OnChange" callback. So create a "Components" folder with a "TextInput.cs" file and paste in the following content -

using System;
using Bridge.Html5;
using Bridge.React;

namespace BridgeReactTutorial.Components
{
  public class TextInput : StatelessComponent<TextInput.Props>
  {
    public TextInput(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.Input(new InputAttributes
      {
        Type = InputType.Text,
        ClassName = props.ClassName,
        Value = props.Content,
        OnChange = e => props.OnChange(e.CurrentTarget.Value)
      });
    }

    public class Props
    {
      public string ClassName;
      public string Content;
      public Action<string> OnChange;
    }
  }
}

(Note: When adding a new ".cs" file to a project, sometimes "System" will sneak back into the list of references in the project - this can confuse Bridge, so ensure that you remove the reference again if it gets added).

Now create another folder in the root of the project called "ViewModels". Add a new file to it; "MessageDetails.cs" and paste in the following content -

namespace BridgeReactTutorial.ViewModels
{
  public class MessageDetails
  {
    public string Title;
    public string Content;
  }
}

Now add another file to the "Components" folder; "MessageEditor.cs" and paste in this:

using System;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.FieldSet(new FieldSetAttributes { ClassName = props.ClassName },
        DOM.Legend(null, string.IsNullOrWhiteSpace(props.Title) ? "Untitled" : props.Title),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new TextInput(new TextInput.Props
        {
          ClassName = "title",
          Content = props.Title,
          OnChange = newTitle => props.OnChange(new MessageDetails
          {
            Title = newTitle,
            Content = props.Content
          })
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new TextInput(new TextInput.Props
        {
          ClassName = "content",
          Content = props.Content,
          OnChange = newContent => props.OnChange(new MessageDetails
          {
            Title = props.Title,
            Content = newContent
          })
        })
      );
    }

    public class Props
    {
      public string ClassName;
      public string Title;
      public string Content;
      public Action<MessageDetails> OnChange;
    }
  }
}

Now things are getting interesting!

This is still a stateless component and so what is rendered depends solely and reliably upon its props data. When it renders, the "Title" value from its props is used to populate both the legend of the fieldset that it renders (unless "Title" is null, blank or white-space-only, in which case the legend text will be "Untitled) and it's used to populate the "Title" TextInput. When either of its TextInputs raises an on-change event, the MessageEditor raises its on-change events with a new MessageDetails instance.

Note that there's no validation yet. We'll get this rough version working first and then add that later.

There are still a few more steps until we have an application, though. We need a container component to render the form in the first place and to deal with on-change events that bubble up. Create another class file within the "Components" folder named "AppContainer.cs" -

using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<object, AppContainer.State>
  {
    public AppContainer() : base(null) { }

    protected override State GetInitialState()
    {
      return new State
      {
        Message = new MessageDetails { Title = "", Content = "" }
      };
    }

    public override ReactElement Render()
    {
      return new MessageEditor(new MessageEditor.Props
      {
        ClassName = "message",
        Title = state.Message.Title,
        Content = state.Message.Content,
        OnChange = newMessage => SetState(new State { Message = newMessage })
      });
    }

    public class State
    {
      public MessageDetails Message;
    }
  }
}

This is the stateful component that will trigger re-renders when required. It doesn't actually require any props data at this time, so the "TProps" type parameter specified on the Component<TProps, TState> base class is just "object".

When the MessageEditor raises an on-change event, the AppContainer will call SetState to replace its current MessageDetails instance with the new one. This will trigger a re-render of the MessageEditor, which will be given the new MessageDetails instance as part of a new props value. It might seem a bit silly to have the MessageEditor pass up a new MessageDetails instance and then to just pass this back down into another MessageEditor, but the idea is to consider the first MessageEditor to be dead now and for the new MessageEditor (with the new MessageDetails) to exist in its place. And each time a stateless component is rendered, it renders simply from its props - there is no data shared between the new instance and the instance it replaces. This, again, makes the components very easy to reason about. And code that is easy to reason about is easy to write and easy to maintain.

Note: If you're au fait with React then you might know that components written as ES6 classes - which seems to be the way that is encouraged at the moment - don't support "GetInitialState" and, instead, specify initial state in the constructor. In the Bridge React bindings, "GetInitialState" should be used and the constructor should NOT be used - the way that the components are initialised by React means that constructors on component classes are not actually executed, so it is important that the constructor ONLY be used to pass the props and/or state to the base class.

The penultimate step is to change "Class1.cs" to render the AppContainer instead of just rendering a "Hi!" div. While we're editing it, let's give it a more official-sounding name. I like the starting point of my application to be called "App" -

using System.Linq;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.Components;

namespace BridgeReactTutorial
{
  public class App
  {
    [Ready]
    public static void Go()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );
      React.Render(new AppContainer(), container);
    }
  }
}

All that's required now is to make it look a little nicer when you view "demo.html", so add the following to "styles.css" -

body
{
  font-family: 'Segoe UI';
  padding: 8px;
}

fieldset
{
  padding: 8px;
  border: 1px solid #f1f1f1;
  border-radius: 4px;
}
fieldset legend
{
  color: blue;
  padding: 0 8px;
}
fieldset.message span.label { padding: 0 8px; }

That's the first major milestone reached! A very basic framework for constructing component hierarchies has been demonstrated, along with a way to handle events and re-render as required. There's nothing very radical, it's just what was described earlier; but it's good to see the theory executed in practice.

I'm far from finished for today, though - I want to add a way to persist messages, a message history component and some validation. Best get cracking!

Message persistence

While I want to simulate a server-based API, where read / write requests aren't instantaneous and we need to think about how to deal with async calls, I don't want the overhead of needing an endpoint to be configured somewhere. So we'll go with a simple interface that will be implemented in an entirely client-side class, that introduces artificial delays to mimic server-calling time.

Create a new folder in the project root called "API" and add a new .cs file "IReadAndWriteMessages.cs", the contents of which should be:

using System.Threading.Tasks;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public interface IReadAndWriteMessages
  {
    Task SaveMessage(MessageDetails message);
  }
}

We'll be using dependency injection to provide the AppContainer with an API implementation. In order to enable unit testing (which will come later) we need to be able to work against an interface. For now, the interface only has a "SaveMessage" method, we'll work on reading message history data later.

Add another file into the "API" folder, "MessageApi.cs" -

using System;
using System.Threading.Tasks;
using Bridge.Html5;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    public Task SaveMessage(MessageDetails message)
    {
      if (message == null)
        throw new ArgumentNullException("message");
      if (string.IsNullOrWhiteSpace(message.Title))
        throw new ArgumentException("A title value must be provided");
      if (string.IsNullOrWhiteSpace(message.Content))
        throw new ArgumentException("A content value must be provided");

      var task = new Task<object>(null);
      Window.SetTimeout(
        () => task.Complete(),
        1000 // Simulate a roundtrip to the server
      );
      return task;
    }
  }
}

Bridge supports the C# "async" keyword and provides its own implementation of Tasks, which are used above to pretend that this class is communicating with a server when a save is requested.

In order to enable saving, the MessageEditor needs a "Save" button and it needs an "on-save" callback to be specified on its props. While saving, the form should be disabled, so the MessageEditor props need a "Disabled" flag as well.

When designing an SPA like this, you need to think about whether you will support "optimistic updates", where clicking Save clears the form and acts as if the save action was instantaneously accepted - but brings it to the user's attention somehow if the save failed or was rejected. I'm going to go for a simpler "pessimistic update" flow, where the form is disabled until the save is acknowledged, at which point the form will be cleared and re-enabled so that a further entry may be written and then saved.

The MessageEditor should now looks like this:

using System;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.FieldSet(new FieldSetAttributes { ClassName = props.ClassName },
        DOM.Legend(null, string.IsNullOrWhiteSpace(props.Title) ? "Untitled" : props.Title),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new TextInput(new TextInput.Props
        {
          ClassName = "title",
          Disabled = props.Disabled,
          Content = props.Title,
          OnChange = newTitle => props.OnChange(new MessageDetails
          {
            Title = newTitle,
            Content = props.Content
          })
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new TextInput(new TextInput.Props
        {
          ClassName = "content",
          Disabled = props.Disabled,
          Content = props.Content,
          OnChange = newContent => props.OnChange(new MessageDetails
          {
            Title = props.Title,
            Content = newContent
          })
        }),
        DOM.Button(
          new ButtonAttributes { Disabled = props.Disabled, OnClick = e => props.OnSave() },
          "Save"
        )
      );
    }

    public class Props
    {
      public string ClassName;
      public string Title;
      public string Content;
      public Action<MessageDetails> OnChange;
      public Action OnSave;
      public bool Disabled;
    }
  }
}

The "Disabled" flag needs to be able to be applied to the TextInput components, so TextInput needs to look like this:

using System;
using Bridge.Html5;
using Bridge.React;

namespace BridgeReactTutorial.Components
{
  public class TextInput : StatelessComponent<TextInput.Props>
  {
    public TextInput(Props props) : base(props) { }

    public override ReactElement Render()
    {
      return DOM.Input(new InputAttributes
      {
        Type = InputType.Text,
        ClassName = props.ClassName,
        Disabled = props.Disabled,
        Value = props.Content,
        OnChange = e => props.OnChange(e.CurrentTarget.Value)
      });
    }

    public class Props
    {
      public string ClassName;
      public bool Disabled;
      public string Content;
      public Action<string> OnChange;
    }
  }
}

This enables the MessageEditor to initiate a save request and for a "Message API" to process the request. Now the AppContainer needs to tie these two aspects together.

Note that the OnSave action on the MessageEditor doesn't provide a new MessageDetails instance - that is because the Title and Content value that are rendered in the MessageEditor could not have been changed since the component was rendered, otherwise an OnChange callback would have been made before OnSave.

Now, the AppContainer gets a bit more interesting because it requires props and state. Its props will be external dependencies that it requires access to, while its state will be a copy of all data that is required to render the form. This is a good time to introduce my React (stateful) component guidelines -

  1. A stateful component's "props" data should only consist of references to external dependencies
  2. A stateful component's "state" data should include everything required to render the component tree, though the props may be required to deal with child components' events

At this point, these rules are going to seem very straight-forward. Later, however, things will get a little more nuanced and I'll re-visit them at that point.

The AppContainer will now become the following -

using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, AppContainer.State>
  {
    public AppContainer(AppContainer.Props props) : base(props) { }

    protected override State GetInitialState()
    {
      return new State
      {
        Message = new MessageDetails { Title = "", Content = "" },
        IsSaveInProgress = false
      };
    }

    public override ReactElement Render()
    {
      return new MessageEditor(new MessageEditor.Props
      {
        ClassName = "message",
        Title = state.Message.Title,
        Content = state.Message.Content,
        OnChange = newMessage => SetState(new State
        {
          Message = newMessage,
          IsSaveInProgress = state.IsSaveInProgress
        }),
        OnSave = async () =>
        {
          SetState(new State { Message = state.Message, IsSaveInProgress = true });
          await props.MessageApi.SaveMessage(state.Message);
          SetState(new State
          {
            Message = new MessageDetails { Title = "", Content = "" },
            IsSaveInProgress = false
          });
        },
        Disabled = state.IsSaveInProgress
      });
    }

    public class Props
    {
      public IReadAndWriteMessages MessageApi;
    }

    public class State
    {
      public MessageDetails Message;
      public bool IsSaveInProgress;
    }
  }
}

You will need to update App.cs to pass a props reference with a MessageApi instance to the AppContainer constructor -

using System.Linq;
using Bridge.Html5;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.Components;

namespace BridgeReactTutorial
{
  public class App
  {
    [Ready]
    public static void Go()
    {
      var container = Document.GetElementById("main");
      container.ClassName = string.Join(
        " ",
        container.ClassName.Split().Where(c => c != "loading")
      );
      React.Render(
        new AppContainer(new AppContainer.Props { MessageApi = new MessageApi() }),
        container
      );
    }
  }
}

With this final piece, we have the outline of a fully functioning application! Granted, its functionality is not particular magnificent, but it has illustrated some important principles. We've seen how a component hierarchy should have a top-level stateful component, with a component tree beneath it of stateless components (note that there are no guidelines required regarding what to put into props and what to put into state when writing a stateless component because props is your only option - another reason why stateless components are so much simpler!). We've also seen how we can deal with dependency injection for these top level components, which are the only point at which more complicated logic appears such as "a save request involves disabling the form, calling a method on the API, waiting for the result and then re-enabling the form". It's worth noting that in the next post, this logic will be moved out of the top-level component in a quest to make components as dumb as possible - but that's jumping ahead, and I want the format of these posts to be that we start simple and then get more complicated only as the benefits of doing so can be made clear.

At this point, however, we have something of a problem. If the "Title" and "Content" text inputs do not both have values, then an exception will be raised by the MessageApi when a save is attempted. To avoid this, we need some..

Validation

I mentioned in the "React components" section that there would be a ValidatedTextInput, but no code had been presented yet. So here we go, nothing in it should be particularly surprising -

using System;
using Bridge.React;

namespace BridgeReactTutorial.Components
{
  public class ValidatedTextInput : StatelessComponent<ValidatedTextInput.Props>
  {
    public ValidatedTextInput(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var className = props.ClassName;
      if (!string.IsNullOrWhiteSpace(props.ValidationMessage))
        className = (className + " invalid").Trim();

      return DOM.Span(new Attributes { ClassName = className },
        new TextInput(new TextInput.Props
        {
          ClassName = props.ClassName,
          Disabled = props.Disabled,
          Content = props.Content,
          OnChange = props.OnChange
        }),
        string.IsNullOrWhiteSpace(props.ValidationMessage)
          ? null
          : DOM.Span(
            new Attributes { ClassName = "validation-message" },
            props.ValidationMessage
          )
      );
    }

    public class Props
    {
      public string ClassName;
      public bool Disabled;
      public string Content;
      public Action<string> OnChange;
      public string ValidationMessage;
    }
  }
}

This allows the MessageEditor to be changed to use these ValidatedTextInputs instead of regular TextInputs, setting the "ValidationMessage" values according to whether the "Content" string has a value -

using System;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageEditor : StatelessComponent<MessageEditor.Props>
  {
    public MessageEditor(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var formIsInvalid =
        string.IsNullOrWhiteSpace(props.Title) ||
        string.IsNullOrWhiteSpace(props.Content);

      return DOM.FieldSet(new FieldSetAttributes { ClassName = props.ClassName },
        DOM.Legend(null, string.IsNullOrWhiteSpace(props.Title) ? "Untitled" : props.Title),
        DOM.Span(new Attributes { ClassName = "label" }, "Title"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "title",
          Disabled = props.Disabled,
          Content = props.Title,
          OnChange = newTitle => props.OnChange(new MessageDetails
          {
            Title = newTitle,
            Content = props.Content
          }),
          ValidationMessage = string.IsNullOrWhiteSpace(props.Title)
            ? "Must enter a title"
            : null
        }),
        DOM.Span(new Attributes { ClassName = "label" }, "Content"),
        new ValidatedTextInput(new ValidatedTextInput.Props
        {
          ClassName = "content",
          Disabled = props.Disabled,
          Content = props.Content,
          OnChange = newContent => props.OnChange(new MessageDetails
          {
            Title = props.Title,
            Content = newContent
          }),
          ValidationMessage = string.IsNullOrWhiteSpace(props.Content)
            ? "Must enter message content"
            : null
        }),
        DOM.Button(
          new ButtonAttributes
          {
            Disabled = props.Disabled || formIsInvalid,
            OnClick = e => props.OnSave()
          },
          "Save"
        )
      );
    }

    public class Props
    {
      public string ClassName;
      public string Title;
      public string Content;
      public Action<MessageDetails> OnChange;
      public Action OnSave;
      public bool Disabled;
    }
  }
}

Now, the "Save" button is disabled if the MessageEditor is disabled (according to its props flag) or if the form entry is invalid. Now, it's not possible for the user to attempt a save that we will know will fail!

(Moving validation logic out of the components is another thing that will come in the move towards dumb-as-possible components, but that's for part two).

To keep things looking pretty, adding the following to "styles.css" -

fieldset.message span.title, fieldset.message span.content { position: relative; }
fieldset.message span.validation-message
{
  position: absolute;
  top: -6px;
  right: 2px;
  padding: 2px 4px;
  font-size: 70%;
  background: #FFF9D8;
  border: 1px solid #EFE9CB;
  border-radius: 2px;
  color: #A8A390;
}
fieldset.message button { margin-left: 8px; }

Message History

What's the point in saving messages if we can't read them back out again? To enable this, the IReadAndWriteMessages needs a "GetMessages" method to accompany "SaveMessage" -

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public interface IReadAndWriteMessages
  {
    Task SaveMessage(MessageDetails message);
    Task<IEnumerable<Tuple<int, MessageDetails>>> GetMessages();
  }
}

This needs implementing in MessageApi -

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bridge.Html5;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.API
{
  public class MessageApi : IReadAndWriteMessages
  {
    private readonly List<Tuple<int, MessageDetails>> _messages;
    public MessageApi()
    {
      _messages = new List<Tuple<int, MessageDetails>>();
    }

    public Task SaveMessage(MessageDetails message)
    {
      if (message == null)
        throw new ArgumentNullException("message");
      if (string.IsNullOrWhiteSpace(message.Title))
        throw new ArgumentException("A title value must be provided");
      if (string.IsNullOrWhiteSpace(message.Content))
        throw new ArgumentException("A content value must be provided");

      var task = new Task<object>(null);
      Window.SetTimeout(
        () =>
        {
          _messages.Add(Tuple.Create(_messages.Count, message));
          task.Complete();
        },
        1000 // Simulate a roundtrip to the server
      );
      return task;
    }

    public Task<IEnumerable<Tuple<int, MessageDetails>>> GetMessages()
    {
      // ToArray is used to return a clone of the message set - otherwise, the caller would
      // end up with a list that is updated when the internal reference within this class
      // is updated (which sounds convenient but it's not the behaviour that would be
      // exhibited if this was really persisting messages to a server somewhere)
      var task = new Task<IEnumerable<Tuple<int, MessageDetails>>>(null);
      Window.SetTimeout(
        () => task.Complete(_messages.ToArray()),
        1000 // Simulate a roundtrip to the server
      );
      return task;
    }
  }
}

Now, we'll need a way to render this information -

using System;
using System.Collections.Generic;
using System.Linq;
using Bridge.React;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class MessageHistory : StatelessComponent<MessageHistory.Props>
  {
    public MessageHistory(Props props) : base(props) { }

    public override ReactElement Render()
    {
      var className = props.ClassName;
      if (!props.Messages.Any())
        className = (className + " zero-messages").Trim();

      // Any time a set of child components is dynamically-created (meaning that the
      // numbers of items may vary from one render to another), each must have a unique
      // "Key" property set (this may be a int or a string). Here, this is simple as
      // each message tuple is a unique id and the contents of that message (and the
      // unique id is ideal for use as a unique "Key" property).
      var messageElements = props.Messages
        .Select(idAndMessage => DOM.Div(new Attributes { Key = idAndMessage.Item1 },
          DOM.Span(new Attributes { ClassName = "title" }, idAndMessage.Item2.Title),
          DOM.Span(new Attributes { ClassName = "content" }, idAndMessage.Item2.Content)
        ));

      return DOM.FieldSet(new FieldSetAttributes { ClassName = className },
        DOM.Legend(null, "Message History"),
        DOM.Div(null, messageElements)
      );
    }

    public class Props
    {
      public string ClassName;
      public IEnumerable<Tuple<int, MessageDetails>> Messages;
    }
  }
}

This highlights an important React principle - where there are sets of dynamic child components, each must be provided a unique key. In the component above, we take "props.Messages" and map the data onto a set of Div elements. It's very possible that different messages will be rendered each time and so this is precisely what is meant by "dynamic child components".

There are two reasons why it's important to provide unique keys - the first is performance; the task of React's Virtual DOM is to take the last component tree and the new component tree and work out what changed, so that the minimum changes may be applied to the browser DOM. In order to do this, it is very helpful for React to be able to track components as they move around within a dynamic set - it can allow it to reuse data internally instead of having to throw away representations of components and recreate them:

When React reconciles the keyed children, it will ensure that any child with key will be reordered (instead of clobbered) or destroyed (instead of reused).

The quote above is from Facebook's docs about Dynamic Children - and so "clobbered" must be an official term!

The second reason why it's important is that component state can only be tracked with a component if the component itself can be tracked by React when dynamic elements move around. I'm not going to dwell too long on this because it's only applicable if you are relying on dynamic components having state, which you shouldn't be since only the top-level component should be stateful (and any component that may be created as a dynamic child component should be stateless).

For our purposes here, providing a unique key for each MessageHistory row is easy because the "GetMessages" method in the API returns a set of tuples, where each pair is a combination of id for the message and the message itself. This was easy to implement with the in-memory message store that we're using for this sample app, but it's also often easy when persisting by sending the data over the wire to a database somewhere; it's common for the database to generate unique ids for each record, and this would be returned in the data from "GetMessages".

Now we have to return to the AppContainer to tie everything together; we need to add the message history data to the AppContainer's state, we need to read the message history after we save and we need to render the message history -

using System;
using System.Collections.Generic;
using Bridge.React;
using BridgeReactTutorial.API;
using BridgeReactTutorial.ViewModels;

namespace BridgeReactTutorial.Components
{
  public class AppContainer : Component<AppContainer.Props, AppContainer.State>
  {
    public AppContainer(AppContainer.Props props) : base(props) { }

    protected override State GetInitialState()
    {
      return new State
      {
        Message = new MessageDetails { Title = "", Content = "" },
        IsSaveInProgress = false,
        MessageHistory = new Tuple<int, MessageDetails>[0]
      };
    }

    public override ReactElement Render()
    {
      return DOM.Div(null,
        new MessageEditor(new MessageEditor.Props
        {
          ClassName = "message",
          Title = state.Message.Title,
          Content = state.Message.Content,
          OnChange = newMessage => SetState(new State
          {
            Message = newMessage,
            IsSaveInProgress = state.IsSaveInProgress,
            MessageHistory = state.MessageHistory
          }),
          OnSave = async () =>
          {
            // Set SaveInProgress to true while the save operation is requested
            SetState(new State {
              Message = state.Message,
              IsSaveInProgress = true,
              MessageHistory = state.MessageHistory
            });
            await props.MessageApi.SaveMessage(state.Message);

            // After the save has completed, clear the message entry form and reset
            // SaveInProgress to false
            SetState(new State {
              Message = new MessageDetails { Title = "", Content = "" },
              IsSaveInProgress = false,
              MessageHistory = state.MessageHistory
            });

            // Then re-load the message history state and re-render when that data arrives
            var allMessages = await props.MessageApi.GetMessages();
            SetState(new State {
              Message = state.Message,
              IsSaveInProgress = state.IsSaveInProgress,
              MessageHistory = allMessages
            });
          },
          Disabled = state.IsSaveInProgress
        }),
        new MessageHistory(new MessageHistory.Props
        {
          ClassName = "history",
          Messages = state.MessageHistory
        })
      );
    }

    public class Props
    {
      public IReadAndWriteMessages MessageApi;
    }

    public class State
    {
      public MessageDetails Message;
      public bool IsSaveInProgress;
      public IEnumerable<Tuple<int, MessageDetails>> MessageHistory;
    }
  }
}

The logic in this component is getting more complicated now, which is down to the event-handling; what needs to happen when this happens and then this happens and then this happens (eg. the user clicks save, we initiate a save request, the API completes the request, we update the UI to clear the form and then start loading the updated message history, then we update the UI with the new message content).

One of the goals going forward will be to separate out this logic, away from the React components. The reason that I've made a couple of mentions of moving towards "dumb components" is that it makes unit testing much easier - everything outside of the React components will be simple C# / JavaScript code, which is always easier to test than UI elements, even when the UI is created using the React library. Another benefit of separating application logic from the UI components is that it makes both sides easier to reason about - and this is another theme that I'll be re-visiting during this mini-series.

It's worth mentioning that, even though it's gotten more complicated, the AppContainer (the only stateful component in the application) still adheres to the stateful component guidelines:

  1. A stateful component's "props" data should only consist of references to external dependencies
  2. A stateful component's "state" data should include everything required to render the component tree, though the props may be required to deal with child components' events

All of the data required to render the UI is present in the state. The props data is only required within "Render" in order to process some of the callbacks from the child components. Any changes that must then be reflected in the UI come through a call to SetState - at the point of the SetState-triggered re-render, all of the data required to generate the child components will, once again, be present entirely within the state data.

To keep things look nice, add the following to "styles.css" -

fieldset.history
{
  opacity: 1;
  transition: opacity .5s ease-in-out;
}
fieldset.history.zero-messages { opacity: 0; }
fieldset.history span.title
{
  padding: 0 8px;
  font-weight: bold;
}

This will have the MessageHistory invisible to begin with, fading in when the first message is available to display.

Coming in Part Two..

I think this makes a good point at which to draw the first part of this series to a close. To be honest, we haven't got very close at all yet to the "The Dan Way" of writing React applications - so far, it's been fairly straight-forward and in-line with the basic React guidelines from Facebook.

Which isn't to save that we haven't covered a lot of good ground! This will serve as a good base from which we can improve things. But we haven't seen the "Flux architecture" at all yet, and have only hinted at why we would want it. I'm not happy with how many of the properties on the various props, state and other data types are presented - one of my pet peeves with APIs is not knowing what can and can't be null; on the TextInput's Props class, the "ClassName" string may be null but the "OnChange" callback must not be. These facts are not clear from just looking at the class. Similarly, it would be nice to know whether or not there are any guarantees about the "Title" and "Content" strings on the MessageDetails class (is it ever really acceptable for them to be null?). Finally, the reading and writing of messages through the MessageApi implementation we have here works fine for one person doing all the writing, but how could we deal with it if the MessageApi simulated a server-based API that received new messages from other uses, either through some sort of polling or through a push mechanism? This is an important question for systems that have to support multiple users.

All of these questions will be answered in later posts, along with further advice to try to help you do what I think React does best - write code that is easier to reason about, and thus easier to read, maintain and extend.

Posted at 23:55

Comments

Easy "PureComponent" React performance boosts for Bridge.Net

React's great strength is that it makes creating UIs simple(r) because you can treat the view as a pure function - often, you essentially give a props reference into a top level component and it works out what to draw. Then, when something changes, you do the same again; trigger a full re-draw and rely upon React's Virtual DOM to work out what changed in an efficient manner and apply those changes to the browser DOM. The browser DOM is slow, which is why interactions with it should be minimised. The Virtual DOM is fast.

The common pre-React way to deal with UIs was to have some code to render the UI in an initial state and then further code that would change the UI based upon user interactions. React reduces these two types of state-handling (initial-display and update-for-specific-interaction) into one (full re-render).

And a lot of the time, the fast Virtual DOM performs quickly enough that you don't have to worry about what it's doing. But sometimes, you may have a UI that is so complicated that it's a lot of work for the Virtual DOM to calculate the diffs to apply to the browser DOM. Or you might have particularly demanding performance requirements, such as achieving 60 fps animations on mobile.

Handily, React has a way for you to give it hints - namely the ShouldComponentUpdate method that components may implement. This method can look at the component's current props and state values and the next props and state values and let React know if any changes are required. The method returns a boolean - false meaning "no, I don't need to redraw, this data looks the same" and true meaning "yes, I need to redraw for this new data". The method is optional, if a component doesn't implement it then it's equivalent to it always returning true. Remember, if a component returns true for "do I need to be redrawn?", the Virtual DOM is still what is responsible for dealing with the update - and it usually deals with it in a very fast and efficient manner. Returning true is not something to necessarily be worried about. However, if you can identify cases where ShouldComponentUpdate can return false then you can save the Virtual DOM from working out whether that component or any of its child components need to be redrawn. If this can be done high up in a deeply-nested component tree then it could save the Virtual DOM a lot of work.

The problem is, though, that coming up with a mechanism to reliably and efficiently compare object references (ie. props and / or state) to determine whether they describe the same data is difficult to do in the general case.

Let me paint a picture by describing a very simple example React application..

The Message Editor Example

Imagine an app that can read a list of messages from an API and allow the user of the app to edit these messages. Each message has "Content" and "Author" properties that are strings. Either of these values may be edited in the app. These messages are part of a message group that has a title - this also may be edited in the app.

(I didn't say that it was a useful or realistic app, it's just one to illustrate a point :)

The way that I like to create React apps is to categorise components as one of two things; a "Container Component" or a "Presentation Component". Presentation Components should be state-less, they should just be handed a props reference and then go off and draw themselves. Any interactions that the user makes with this component or any of its child components are effectively passed up (via change handlers on the props reference) until it reaches a Container Component. The Container Component will translate these interaction into actions to send to the Dispatcher. Actions will be handled by a store (that will be listening out for Dispatcher actions that it's interested in). When a store handles an action, it emits a change event. The Container Component will be listening out for change events on stores that it is interested in - when this happens, the Container Component will trigger a re-render of itself by updating its state based upon data now available in the store(s) it cares about. This is a fairly standard Flux architecture and, I believe, the terms "Container Component" / "Presentation Component are in reasonably common use (I didn't make them up, I just like the principle - one of the articles that I've read that uses these descriptions is Component Brick and Mortar: The React documentation I wish I had a year ago).

So, for my example app, I might have a component hierarchy that looks this:

AppContainer
  Title
    TextInput
      Input
  MessageList
    MessageRow
      TextInput
        Input
      TextInput
        Input
    MessageRow
      TextInput
        Input
      TextInput
        Input

There will be as many "MessageRow" components as there are messages to edit. Input is a standard React-rendered element and all of the others (AppContainer, Title, MessageList, MessageRow and TextInput) are custom components.

(Note: This is not a sufficiently deeply-nested hierarchy that React would have any problems with rendering performance, it's intended to be just complicated enough to demonstrate the point that I'm working up to).

The AppContainer is the only "Container Component" and so is the only component that has a React state reference as well as props. A state reference is, essentially, what prevents a component from being what you might consider a "pure function" - where the props that are passed in are all that affects what is rendered out. React "state" is required to trigger a re-draw of the UI, but it should be present in as few places as possible - ie. there should only be one, or a small number of, top level component(s) that have state. Components that render only according to their props data are much easier to reason about (and hence easier to write, extend and maintain).

My Bridge.NET React bindings NuGet package makes it simple to differentiate between stateful (ie. Container) components and stateless (ie. Presentation) components as it has both a Component<TProps, TState> base class and a StatelessComponent<TProps> base class - you derive from the appropriate one when you create custom components (for more details, see React (and Flux) with Bridge.net - Redux).

To start with the simplest example, below is the TextInput component. This just renders a text Input with a specified value and communicates up any requests to change that string value via an "OnChange" callback -

public class TextInput : StatelessComponent<TextInput.Props>
{
  public TextInput(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Input(new InputAttributes
    {
      Type = InputType.Text,
      Value = props.Content,
      OnChange = OnTextChange
    });
  }

  private void OnTextChange(FormEvent<InputElement> e)
  {
    props.OnChange(e.CurrentTarget.Value);
  }

  public class Props
  {
    public string Content { get; set; }
    public Action<string> OnChange { get; set; }
  }
}

It is fairly easy to envisage how you might try to implement "ShouldComponentUpdate" here - given a "this is the new props value" reference (which gets passed into ShouldComponentUpdate as an argument called "nextProps") and the current props reference, you need only look at the "Content" and "OnChange" references on the current and next props and, if both Content/Content and OnChange/OnChange references are the same, then we can return false (meaning "no, we do not need to re-draw this TextInput").

(Two things to note here: Firstly, it is not usually possible to directly compare the current props reference with the "nextProps" reference because it is common for the parent component to create a new props instance for each proposed re-render of a child component, rather than re-use a previous props instance - so the individual property values within the props references may all be consistent between the current props and nextProps, but the actual props references will usually be distinct. Secondly, the Bridge.NET React bindings only support React component life cycle method implementations on custom components derived from Component<TProps, TState> classes and not those derived from StatelessComponent<TProps>, so you couldn't actually write your own "ShouldComponentUpdate" for a StatelessComponent - but that's not important here, we're just working through a thought experiment).

Now let's move on to the MessageList and MessageRow components, since things get more complicated there -

public class MessageList : StatelessComponent<MessageList.Props>
{
  public MessageList(Props props) : base(props) { }

  public override ReactElement Render()
  {
    var messageRows = props.IdsAndMessages
      .Select(idAndMessage => new MessageRow(new MessageRow.Props
      {
        Key = idAndMessage.Item1,
        Message = idAndMessage.Item2,
        OnChange = newMessage => props.OnChange(idAndMessage.Item1, newMessage)
      }));
    return DOM.Div(
      new Attributes { ClassName = "message-list" },
      messageRows
    );
  }

  public class Props
  {
    public Tuple<int, MessageEditState>[] IdsAndMessages;
    public Action<int, MessageEditState> OnChange;
  }
}

public class MessageRow : StatelessComponent<MessageRow.Props>
{
  public MessageRow(Props props) : base(props) { }

  public override ReactElement Render()
  {
    // Note that the "Key" value from the props reference does not explicitly need
    // to be mentioned here, the React bindings will deal with it (it is important
    // to give dynamic children components unique key values, but it is handled by
    // the bindings and the React library so long as a "Key" property is present
    // on the props)
    // - See https://facebook.github.io/react/docs/multiple-components.html for
    //   more details
    return DOM.Div(new Attributes { ClassName = "message-row" },
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Content,
        OnChange = OnContentChange
      }),
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Author,
        OnChange = OnAuthorChange
      })
    );
  }

  private void OnContentChange(string newContent)
  {
    props.OnChange(new MessageEditState
    {
      Content = newContent,
      Author = props.Message.Author
    });
  }
  private void OnAuthorChange(string newAuthor)
  {
    props.OnChange(new MessageEditState
    {
      Content = props.Message.Content,
      Author = newAuthor
    });
  }

  public class Props
  {
    public int Key;
    public MessageEditState Message;
    public Action<MessageEditState> OnChange;
  }
}

public class MessageEditState
{
  public string Content;
  public string Author;
}

If the MessageList component wanted to implement "ShouldComponentUpdate" then its job is more difficult as it has an array of message data to check. It could do one of several things - the first, and most obviously accurate, would be to perform a "deep compare" of the arrays from the current props and the "nextProps"; ensuring firstly that there are the same number of items in both and then comparing each "Content" and "Author" value in each item of the arrays. If everything matches up then the two arrays contain the same data and (so long as the "OnChange" callback hasn't changed) the component doesn't need to re-render. Avoiding re-rendering this component (and, subsequently, any of its child components) would be a big win because it accounts for a large portion of the total UI. Not re-rendering it would give the Virtual DOM much less work to do. But would a deep comparison of this type actually be any cheaper than letting the Virtual DOM do what it's designed to do?

The second option is to presume that whoever created the props references would have re-used any MessageEditState instances that haven't changed. So the array comparison could be reduced to ensuring that the current and next props references both have the same number of elements and then performing reference equality checks on each item.

The third option is to presume that whoever created the props reference would have re-used the array itself if the data hadn't changed, meaning that a simple reference equality check could be performed on the current and next props' arrays.

The second and third options are both much cheaper than a full "deep compare" but they both rely upon the caller following some conventions. This is why I say that this is a difficult problem to solve for the general case.

Immutability to the rescue

There is actually another option to consider, the object models for the props data could be rewritten to use immutable types. These have the advantage that if you find that two references are equal then they are guaranteed to contain the same data. They also have the advantage that it's much more common to re-use instances to describe the same data - partly because there is some overhead to initialising immutable types and partly because there is no fear that "if I give this reference to this function, I want to be sure that it can't change the data in my reference while doing its work" because it is impossible to change an immutable reference's data. (I've seen defensively-written code that clones mutable references that it passes into other functions, to be sure that no other code can change the data in the original reference - this is never required with immutable types).

Conveniently, I've recently written a library to use with Bridge.NET which I think makes creating and working with immutable types easier than C# makes it on its own. I wrote about it in "Friction-less immutable objects in Bridge (C# / JavaScript) applications" but the gist is that you re-write MessageEditState as:

// You need to pull in the "ProductiveRage.Immutable" NuGet package to use IAmImmutable
public class MessageEditState : IAmImmutable
{
  public MessageEditState(string content, string author)
  {
    this.CtorSet(_ => _.Content, content);
    this.CtorSet(_ => _.Author, author);
  }
  public string Content { get; private set; }
  public string Author { get; private set; }
}

It's still a little more verbose than the mutable version, admittedly, but I'm hoping to convince you that it's worth it (if you need convincing!) for the benefits that we'll get.

When you have an instance of this new MessageEditState class, if you need to change one of the properties, you don't have to call the constructor each time to get a new instance, you can use the "With" extension methods that may be called on any IAmImmutable instance - eg.

var updatedMessage = message.With(_ => _.Content, "New information");

This would mean that the change handlers from MessageRow could be altered from:

private void OnContentChange(string newContent)
{
  props.OnChange(new MessageEditState
  {
    Content = newContent,
    Author = props.Message.Author
  });
}
private void OnAuthorChange(string newAuthor)
{
  props.OnChange(new MessageEditState
  {
    Content = props.Message.Content,
    Author = newAuthor
  });
}

and replaced with:

private void OnContentChange(string newContent)
{
  props.OnChange(props.Message.With(_ => _.Content, newContent));
}
private void OnAuthorChange(string newAuthor)
{
  props.OnChange(props.Message.With(_ => _.Author, newAuthor));
}

Immediately, the verbosity added to MessageEditState is being offset with tidier code! (And it's nice not having to set both "Content" and "Author" when only changing one of them).

The "With" method also has a small trick up its sleeve in that it won't return a new instance if the new property value is the same as the old property value. This is an eventuality that could happen in the code above as an "Input" element rendered by React will raise an "OnChange" event for any action that might have altered the text input's content. For example, if you had a text box with the value "Hello" in it and you selected all of that text and then pasted in text from the clipboard over the top of it, if the clipboard text was also "Hello" then the "OnChange" event will be raised, even though the actual value has not changed (it was "Hello" before and it's still "Hello" now). The "With" method will deal with this, though, and just pass the same instance straight back out. This is an illustration of the "reuse of instances for unchanged data" theme that I alluded to above.

The next step would be to change the array type in the MessageList.Props type from

public Tuple<int, MessageEditState>[] IdsAndMessages;

to

public NonNullList<Tuple<int, MessageEditState>> IdsAndMessages;

The NonNullList class is also in the ProductiveRage.Immutable NuGet package. It's basically an immutable IEnumerable that may be used in Bridge.NET projects. A simple example of it in use is:

// Create a new set of values (the static "Of" method uses type inference to determine
// the type of "T" in the returned "NonNullList<T>" - since 1, 2 and 3 are all ints, the
// "numbers" reference will be of type "NonNullList<int>")
var numbers = NonNullList.Of(1, 2, 3);

// SetValue takes an index and a new value, so calling SetValue(2, 4) on a set
// containing 1, 2, 3 will return a new set containing the values 1, 2, 4
numbers = numbers.SetValue(2, 4);

// Calling SetValue(2, 4) on a set containing values 1, 2, 4 does not require any
// changes, so the input reference is passed straight back out
numbers = numbers.SetValue(2, 4);

As with IAmImmutable instances we get two big benefits - we can rely on reference equality comparisons more often, since the data with any given reference can never change, and references will be reused in many cases if operations are requested that would not actually change the data. (It's worth noting that the guarantees fall apart if any property on an IAmImmutable reference is a of a mutable type, similarly if a NonNullList has elements that are a mutable type, or that have nested properties that are of a mutable type.. but so long as immutability is used "all the way down" then all will be well).

If this philosophy was followed, then suddenly the "ShouldComponentUpdate" implementation for the MessageList component would be very easy to write - just perform reference equality comparisons on the "IdsAndMessages" and "OnChange" values on the current props and on the nextProps. While solving the problem for the general case is very difficult, solving it when you introduce some constraints (such as the use of immutable and persistent data types) can be very easy!

If we did implement this MessageList "ShouldComponentUpdate" method, then we could be confident that when a user makes changes to the "Title" text input that the Virtual DOM would not have to work out whether the MessageList or any of its child components had changed - because we'd have told the Virtual DOM that they hadn't (because the "IdsAndMessages" and "OnChange" property references wouldn't have changed).

We could take this a step further, though, and consider the idea of implementing "ShouldComponentUpdate" on other components - such as MessageRow. If the user edits a text value within one row, then the MessageList will have to perform some re-rendering work, since one of its child components needs to be re-rendered. But there's no need for any of the other rows to re-render, it could be just the single row in which the change was requested by the user.

So the MessageRow could look at its props values and, if they haven't changed between the current props and the nextProps, then inform React (via "ShouldComponentUpdate") that no re-render is required.

And why not go even further and just do this on all Presentation Components? The TextInput could avoid the re-render of its child Input if the props' "Content" and "OnChange" reference are not being updated.

Introducing the Bridge.React "PureComponent"

To make this easy, I've added a new base class to the React bindings (available in 1.4 of Bridge.React); the PureComponent<TProps>.

This, like the StatelessComponent<TProps>, is very simple and does not support state and only allows the "Render" method to be implemented - no other React lifecycle functions (such "ComponentWillMount", "ShouldComponentUpdate", etc..) may be defined on components deriving from this class.

The key difference is that it has its own "ShouldComponentUpdate" implementation that presumes that the props data is immutable and basically does what I've been describing above automatically - when React checks "ShouldComponentUpdate", it will look at the "props" and "nextProps" instances and compare their property values. (It also deals with the cases where one or both of them are null, in case you want components whose props reference is optional).

This is not an original idea, by a long shot. I first became aware of people doing this in 2013 when I read The Future of JavaScript MVC Frameworks, which was talking about using ClojureScript and its React interface "Om". More recently, I was reading Performance Engineering with React (Part 1), which talks about roughly the same subject but with vanilla JavaScript. And, of course, Facebook has long had its PureRenderMixin - though mixins can't be used with ES6 components (which seems to be the approach to writing components that Facebook is pushing at the moment).

So, this is largely just making it easy it when writing React applications with Bridge. However, using Bridge to do this does give us some extra advantages (on top of the joy of being able to write React apps in C#!). In the code earlier (from the MessageRow Render method) -

new TextInput(new TextInput.Props
{
  Content = props.Message.Content,
  OnChange = OnContentChange
})

Bridge will bind the "OnContentChange" method to the current MessageRow instance so that when it is called by the TextInput's "OnChange" event, "this" is the MessageRow and not the TextInput (which is important because OnContentChange needs to access the "props" reference scoped to the MessageRow).

This introduces a potential wrinkle in our plan, though, as this binding process creates a new JavaScript method each time and means that each time the TextInput is rendered, the "OnChange" reference is new. So if we try to perform simple reference equality checks on props values, then we won't find the current "OnChange" and the new "OnChange" to be the same.

This problem is mentioned in the "Performance Engineering" article I linked above:

Unfortunately, each call to Function.bind produces a new function.. No amount of prop checking will help, and your component will always re-render.

..

The simplest solution we've found is to pass the unbound function.

When using Bridge, we don't have the option of using an unbound function since the function-binding is automatically introduced by the C#-to-JavaScript translation process. And it's very convenient, so it's not something that I'd ideally like to have to workaround.

Having a dig through Bridge's source code, though, revealed some useful information. When Bridge.fn.bind is called, it returns a new function (as just discussed).. but with some metadata attached to it. When it returns a new function, it sets two properties on it "$scope" and "$method". The $scope reference is what "this" will be set to when the bound function is called and the $method reference is the original function that is being bound. This means that, when the props value comparisons are performed, if a value is a function and it the reference equality comparison fails, a fallback approach may be attempted - if both functions have $scope and $method references defined then compare them and, if they are both consistent between the function value on the current props and the function value on the nextProps, then consider the value to be unchanged.

The PureComponent's "ShouldComponentUpdate" implementation deals with this automatically, so you don't have to worry about it.

It's possibly worth noting that the "Performance Engineering" post did briefly consider something similar -

Another possibility we've explored is using a custom bind function that stores metadata on the function itself, which in combination with a more advanced check function, could detect bound functions that haven't actually changed.

Considering that Bridge automatically includes this additional metadata, it seemed to me to be sensible to use it.

There's one other equality comparison that is supported; as well as simple referential equality and the function equality gymnastics described above, if both of the values are non-null and the first has an "Equals" function then this function will be considered. This means that any custom "Equals" implementations that you define on classes will be automatically taken into consideration by the PureComponent's logic.

Another Bridge.NET bonus: Lambda support

When I started writing this post, there was going to be a section here with a warning about using lambdas as functions in props instances, rather than using named functions (which the examples thus far have done).

As with bound functions, anywhere that an anonymous function is present in JavaScript, it will result in a new function value being created. If, for example, we change the MessageRow class from:

public class MessageRow : PureComponent<MessageRow.Props>
{
  public MessageRow(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Div(new Attributes { ClassName = "message-row" },
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Content,
        OnChange = OnContentChange
      }),
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Author,
        OnChange = OnAuthorChange
      })
    );
  }

  private void OnContentChange(string newContent)
  {
    props.OnChange(props.Message.With(_ => _.Content, newContent));
  }
  private void OnAuthorChange(string newAuthor)
  {
    props.OnChange(props.Message.With(_ => _.Author, newAuthor));
  }

  public class Props
  {
    public int Key;
    public MessageEditState Message;
    public Action<MessageEditState> OnChange;
  }
}

to:

public class MessageRow : PureComponent<MessageRow.Props>
{
  public MessageRow(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Div(new Attributes { ClassName = "message-row" },
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Content,
        OnChange = newContent =>
          props.OnChange(props.Message.With(_ => _.Content, newContent))
      }),
      new TextInput(new TextInput.Props
      {
        Content = props.Message.Author,
        OnChange = newAuthor =>
          props.OnChange(props.Message.With(_ => _.Author, newAuthor))
      })
    );
  }

  public class Props
  {
    public int Key;
    public MessageEditState Message;
    public Action<MessageEditState> OnChange;
  }
}

then there would be problems with the "OnChange" props values specified because each new lambda - eg..

OnChange = newContent =>
  props.OnChange(props.Message.With(_ => _.Content, newContent))

would result in a new JavaScript function being passed to Bridge.fn.bind every time that it was called:

onChange: Bridge.fn.bind(this, function (newContent) {
  this.getprops().onChange(
    ProductiveRage.Immutable.ImmutabilityHelpers.$with(
       this.getprops().message,
      function (_) { return _.getContent(); },
      newContent
    )
  );
})

And this would prevent the PureComponent's "ShouldComponentUpdate" logic from being effective, since the $method values from the current props "OnChange" and the nextProps "OnChange" bound functions would always be different.

I was quite disappointed when I realised this and was considering trying to come up with some sort of workaround - maybe calling "toString" on both $method values and comparing their implementations.. but I couldn't find definitive information about the performance implications of this and I wasn't looking forward to constructing my own suite of tests to investigate any potential performance impact of this across different browsers and different browser versions.

My disappointment was two-fold: firstly, using the lambdas allows for more succinct code and less syntactic noise - since the types of the lambda's argument(s) and return value (if any) are inferred, rather than having to be explicitly typed out.

newContent => props.OnChange(props.Message.With(_ => _.Content, newContent))

is clearly shorter than

private void OnContentChange(string newContent)
{
  props.OnChange(props.Message.With(_ => _.Content, newContent));
}

The other reason that I was deflated upon realising this was that it meant that the "ShouldComponentUpdate" implementation would, essentially, silently fail for components that used lambdas - "ShouldComponentUpdate" would return true in cases where I would like it to return false. There would be no compiler error and the UI code would still function, but it wouldn't be as efficient as it could be (the Virtual DOM would have to do more work than necessary).

Instead, I had a bit of a crazy thought.. lambdas like this, that only need to access their own arguments and the "this" reference, could be "lifted" into named functions quite easily. Essentially, I'm doing this manually by writing methods such as "OnContentChange". But could the Bridge translator do something like this automatically - take those C# lambdas and convert them into named functions in JavaScript? That way, I would get the benefit of the succinct lambda format in C# and the PureComponent optimisations would work.

Well, once again the Bridge.NET Team came through for me! I raised a Feature Request about this, explained what I'd like in an ideal world (and why) and five days later there was a branch on GitHub where I could preview changes that did precisely what I wanted!

This is not just an example of fantastic support from the Bridge Team, it is also, I believe, an incredible feature for Bridge and a triumph for writing front-end code in C#! Having this "translation step" from C# to JavaScript provides the opportunity for handy features to be included for free - earlier we saw how the insertion of Bridge.fn.bind calls by the translator meant that we had access to $method and $scope metadata (which side-steps one of the problems that were had by the author of Performance Engineering with React) but, here, the translation step can remove the performance overhead that anonymous functions were going to cause for our "ShouldComponentUpdate" implementation, without there being any burden on the developer writing the C# code.

It's also worth considering the fact that every allocation made in JavaScript is a reference that needs to be tidied up by the browser's garbage collector at some point. A big reason why judicious use of "ShouldComponentUpdate" can make UIs faster is that there is less work for the Virtual DOM to do, but it also eases the load on the garbage collector because none of the memory allocations need to be made for child components of components that do not need to be re-rendered. Since anonymous JavaScript functions are created over and over again (every time that the section of code that declares the anonymous function is executed), lifting them into named functions means that there will be fewer allocations in your SPA and hence even less work for the garbage collector to do.

Note: As of the 11th of February 2016, this Bridge.NET improvement has not yet been made live - but their release cycles tend to be fairly short and so I don't imagine that it will be very long until it is included in an official release. If you were desperate to write any code with PureComponent before then, you could either avoid lambdas in your C# code or you could use lambdas now, knowing that the PureComponent won't be giving you the full benefit immediately - but that you WILL get the full benefit when the Bridge Team release the update.

So it's an unequivocable success then??

Well, until it transpired that the Bridge translator would be altered to convert these sorts of lambdas into named functions, I was going to say "this is good, but..". However, with that change in sight, I'm just going to say outright "yes, and I'm going to change all classes that derive from StatelessComponent in my projects to derive from PureComponent". This will work fine, so long as your props references are all immutable (meaning that they are immutable all the way down - you shouldn't have, say, a props property that is an immutable NonNullList of references, but where those references have mutable properties).

And, if you're not using immutable props types - sort yourself out! While a component is being rendered (according to the Facebook React Tutorial):

props are immutable: they are passed from the parent and are "owned" by the parent

So, rather than having props only be immutable during component renders (by a convention that the React library enforces), why not go whole-hog and use fully immutable classes to describe your props types - that way props are fully immutable and you can use the Bridge.React's PureComponent to get performance boosts for free!

(Now seems like a good time to remind you of my post "Friction-less immutable objects in Bridge (C# / JavaScript) applications", which illustrates how to use the ProductiveRage.Immutable NuGet package to make defining immutable classes just that bit easier).

Posted at 20:11

Comments

Friction-less immutable objects in Bridge (C# / JavaScript) applications

One of the posts that I've written that got the most "audience participation*" was one from last year "Implementing F#-inspired 'with' updates for immutable classes in C#", where I spoke about trying to ease the burden in C# or representing data with immutable classes by reducing the repetitive typing involved.

* (I'd mis-remembered receiving more criticism about this than I actually did - now that I looking back at the comments left on the post and on reddit, the conversations and observations are pretty interesting and largely constructive!)

The gist was that if I wanted to have a class that represented, for the sake of a convoluted example, an employee that had a name, a start-of-employment date and some notes (which are optional and so may not be populated) then we might have something like the following:

public class EmployeeDetails
{
  public EmployeeDetails(string name, DateTime startDate, string notesIfAny)
  {
    if (string.IsNullOrWhiteSpace(name))
      throw new ArgumentException("name");

    Name = name.Trim();
    StartDate = startDate;
    NotesIfAny = (notesIfAny == null) ? null : notesIfAny.Trim();
  }

  /// <summary>
  /// This will never be null or blank, it will not have any leading or trailing whitespace
  /// </summary>
  public string Name { get; private set; }

  public DateTime StartDate { get; private set; }

  /// <summary>
  /// This will be null if it has not value, otherwise it will be a non-blank string with no
  /// leading or trailing whitespace
  /// </summary>
  public string NotesIfAny { get; private set; }
}

If we wanted to update a record with some notes where previously it had none then we'd need to create a new instance, something like:

var updatedEmployee = new EmployeeDetails(
  employee.Name,
  employee.StartDate,
  "Awesome attitude!"
);

This sort of thing (calling the constructor explicitly) gets old quickly, particularly if the class gets extended in the future since then anywhere that did something like this would have to add more arguments to the constructor call.

So an alternative is to include "With" functions in the class -

public class EmployeeDetails
{
  public EmployeeDetails(string name, DateTime startDate, string notesIfAny)
  {
    if (string.IsNullOrWhiteSpace(name))
      throw new ArgumentException("name");

    Name = name.Trim();
    StartDate = startDate;
    NotesIfAny = (notesIfAny == null) ? null : notesIfAny.Trim();
  }

  /// <summary>
  /// This will never be null or blank, it will not have any leading or trailing whitespace
  /// </summary>
  public string Name { get; private set; }

  public DateTime StartDate { get; private set; }

  /// <summary>
  /// This will be null if it has not value, otherwise it will be a non-blank string with no
  /// leading or trailing whitespace
  /// </summary>
  public string NotesIfAny { get; private set; }

  public EmployeeDetails WithName(string value)
  {
      return (value == Name) ? this : new EmployeeDetails(value, StartDate, NotesIfAny);
  }
  public EmployeeDetails WithStartDate(DateTime value)
  {
      return (value == StartDate) ? this : new EmployeeDetails(Name, value, NotesIfAny);
  }
  public EmployeeDetails WithNotesIfAny(string value)
  {
      return (value == NotesIfAny) ? this : new EmployeeDetails(Name, StartDate, value);
  }
}

Now the update code is more succinct -

var updatedEmployee = employee.WithNotesIfAny("Awesome attitude!");

Another benefit of this approach is that the With functions can include a quick check to ensure that the new value is not the same as the current value - if it is then there's no need to generate a new instance, the current instance can be returned straight back out. This saves generating a new object reference and it makes it easier to rely upon simple reference equality tests when determining whether data has changed - eg.

var updatedEmployee = employee.WithNotesIfAny("Awesome attitude!");
var didEmployeeAlreadyHaveAwesomeAttitude = (updatedEmployee == employee);

Last year's post went off on a few wild tangents but basically was about allowing something like the following to be written:

public class EmployeeDetails
{
  public EmployeeDetails(string name, DateTime startDate, string notesIfAny)
  {
    if (string.IsNullOrWhiteSpace(name))
      throw new ArgumentException("name");

    Name = name.Trim();
    StartDate = startDate;
    NotesIfAny = (notesIfAny == null) ? null : notesIfAny.Trim();
  }

  /// <summary>
  /// This will never be null or blank, it will not have any leading or trailing whitespace
  /// </summary>
  public string Name { get; private set; }

  public DateTime StartDate { get; private set; }

  /// <summary>
  /// This will be null if it has not value, otherwise it will be a non-blank string with no
  /// leading or trailing whitespace
  /// </summary>
  public string NotesIfAny { get; private set; }

  public EmployeeDetails With(
    Optional<string> name = new Optional<string>(),
    Optional<DateTime> startDate = new Optional<DateTime>(),
    Optional<Optional<string>> notesIfAny = new Optional<Optional<string>>())
  {
    return DefaultUpdateWithHelper.GetGenerator<EmployeeDetails>()(
      this, name, startDate, notesIfAny
    );
  }
}

It allowed you to include a single "With" function that could change one or more of the properties in a single call like this:

var updatedEmployee = employee.With(name: "Jimbo", notesIfAny: "So lazy!");

And it would do it with magic, so you wouldn't have to write all of the "return-same-instance-if-no-values-changed" logic and it would.. erm.. well, to be honest, I've forgotten some of the finer details! But I remember that it was fun messing around with, getting my hands dirty with reflection, compiled LINQ expressions, stack-trace-sniffing (and some required JIT-method-inlining-disabling).

A couple of weeks later I wrote a follow-up, taking on board some of the feedback and criticisms in the comments and doing some performance testing. One of the ways I came up with to create the "magic With method" was only twice as slow as writing it by hand.. which, now, doesn't sound all that awesome - twice as slow is often a bad thing, but I was quite proud of it at the time!

Immutable Classes in 2015

Recently, I've been making Bridge.NET applications and I've been favouring writing immutable types for the messages passed around the system. And, again, I've gotten a bit bored of writing the same lines of code over and over -

if (value == null)
  throw new ArgumentNullException("value");

and

/// <summary>
/// This will never be null
/// </summary>

and

/// <summary>
/// This will never be null, nor blank, nor have any leading or trailing whitespace
/// </summary>

Never mind contemplating writing all of those "WithName", "WithStartDate" methods (checking in them that the values have actually changed and returning the same instance back out if not). I love the benefits of having these immutable types (reducing places where it's possible for state to change makes reasoning about code soooooooo much easier) but I'm getting tired of banging out the same constructs and sentences! follows a

So I've started on a new tack. I want to find those places where repetition is getting me down and I want to reduce it as much as possible. But I don't want to sacrifice my validation checks or the guarantees of immutability. And, again, to put this into context - I'm going to be concentrating on the classes that I write in C# but that Bridge.NET then translates into JavaScript, so there are different considerations to take into account. First of which being that Bridge doesn't support reflection and so none of the crazy stuff I was doing in "pure" C# will be possible! Not in the same way that I wrote it last time, at least..

Before I get into any silly stuff, though, I want to talk about a couple of techniques that hopefully aren't too controversial and that I think have improved my code as well as requiring me to type less.

First off is a variation of the "Optional" struct that I used in my C# library last time. Previously, as illustrated in the code at the top of this post, I was relying on argument names and comments to indicate when values may and may not be null. The "Name" property has a comment saying that it will not be null while the "NotesIfAny" property has a comment saying that it might be null - and it follows a convention of having an "IfAny" suffix, which suggests that it might not always have a value.

Instead, I want to move to assuming that all references are non-null and that values that may be null have their type wrapped in an Optional struct.

This would change the EmployeeDetails example to look like this:

public class EmployeeDetails
{
  public EmployeeDetails(string name, DateTime startDate, Optional<string> notes)
  {
    if (string.IsNullOrWhiteSpace(name))
      throw new ArgumentException("name");
    Name = name.Trim();
    StartDate = startDate;
    Notes = !notes.IsDefined || (notes.Value.Trim() == "") ? null : notes.Value.Trim();
  }
  public string Name { get; private set; }
  public DateTime StartDate { get; private set; }
  public Optional<string> Notes { get; private set; }
}

The "IfAny" suffix is gone, along with all of the comments about null / non-null. Now the type system indicates whether a value may be null (in which case it will be wrapped in an Optional) or not.

(Note: I'll talk more about Optional later in this post - there's nothing too revolutionary or surprising in there, but it will distract from what I'm trying to build up to here).

We have lost something, though, because in the earlier code the Name and Notes fields had comments that stated that the values (if non-null, in the case of Notes) would not be blank and would not have any leading or trailing whitespace. This information is no longer included in comments, because I want to lose the comments. But, if I've solved the null / non-null problem by leveraging the type system, why not do the same with the non-blank-trimmed strings?

Introducing..

public class NonBlankTrimmedString
{
  public NonBlankTrimmedString(string value)
  {
    if (string.IsNullOrWhiteSpace(value))
      throw new ArgumentException("Must be non-null and have some non-whitespace content");
    Value = value.Trim();
  }

  /// <summary>
  /// This will never have any leading or trailing whitespace, it will never be blank
  /// </summary>
  public string Value { get; private set; }

  public static implicit operator NonBlankTrimmedString(string value)
  {
    return new NonBlankTrimmedString(value);
  }
  public static implicit operator string(NonBlankTrimmedString value)
  {
    return value.Value;
  }
}

Ok, so it looks like the comments are back.. but the idea is that the "will never have any leading or trailing whitespace, it will never be blank" need only appear once (in this class) and not for every property that should be non-null and non-blank and not-have-any-leading-or-trailing-whitespace.

Now the EmployeeDetails class can become:

public class EmployeeDetails
{
  public EmployeeDetails(
      NonBlankTrimmedString name,
    DateTime startDate,
    Optional<NonBlankTrimmedString> notes)
  {
    if (name == null)
      throw new ArgumentNullException("name");
    Name = name;
    StartDate = startDate;
    Notes = notes;
  }
  public NonBlankTrimmedString Name { get; private set; }
  public DateTime StartDate { get; private set; }
  public Optional<NonBlankTrimmedString> Notes { get; private set; }
}

This looks a lot better. Not only is there less to read, there was less repetitive code (and comments) to write but the same information is still available for someone reading / using the code. In fact, I think that it's better on that front now because the constructor signature and the property types themselves communicate this information - which makes it harder to ignore than a comment does. And the type system is the primary reason that I want to write my front-end applications in C# rather than JavaScript!

However, there are still a couple of things that I'm not happy with. Firstly, in an ideal world, the constructors would magically have if-null-then-throw conditions injected for every argument - there are no arguments that should be null now; Optional is a struct and so can never be null, while any references that could be null should be wrapped in an Optional. One way to achieve that this in regular C# is with IL rewriting but I'm not a huge fan of that because I have suspicions about PostSharp (that I should probably revisit one day because I'm no longer completely sure what grounds they're based on). But, aside from that, it would be use when writing C# for Bridge, since IL doesn't come into the process - C# source code is translated into JavaScript and IL isn't involved!

Secondly, I need to tackle the "With" function(s) and I'd like to make that as painless as possible, really. Writing them all by hand is tedious.

Get to the point, already!

So.. I've been playing around and I've written a Bridge.NET library that allows me to write something like this:

public class EmployeeDetails : IAmImmutable
{
  public EmployeeDetails(
    NonBlankTrimmedString name,
    DateTime startDate,
    Optional<NonBlankTrimmedString> notes)
  {
    this.CtorSet(_ => _.Name, name);
    this.CtorSet(_ => _.StartDate, startDate);
    this.CtorSet(_ => _.Notes, notes);
  }
  public NonBlankTrimmedString Name { get; private set; }
  public DateTime StartDate { get; private set; }
  public Optional<NonBlankTrimmedString> Notes { get; private set; }
}

Which is not too bad! Unfortunately, yes, there is some duplication still - there are three places that each of the properties are mentioned; in the constructor argument list, in the constructor body and as public properties. However, I think that this is the bare minimum number of times that they could be repeated without sacrificing any type guarantees. The constructor has to accept a typed argument list and it has to somehow map them onto properties. The properties have to repeat the types so that any one accessing those property values know what they're getting.

But let's talk about the positive things, rather than the negative (such as the fact that while the format shown above is fairly minimal, it's still marginally more complicated in appearance than a simple mutable type). Actually.. maybe we should first talk about the weird things - like what is this "CtorSet" method?

"CtorSet" is an extension method that sets a specified property on the target instance to a particular value. It has the following signature:

public static void CtorSet<T, TPropertyValue>(
  this T source,
  Func<T, TPropertyValue> propertyIdentifier,
  TPropertyValue value)
    with T : IAmImmutable

It doesn't just set it, though, it ensures that the value is not null first and throws an ArgumentNullException if it is. This allows me to avoid the repetitive and boring if-null-then-throw statements. I don't need to worry about cases where I do want to allow nulls, though, because I would use an Optional type in that case, which is a struct and so never can be null!

The method signature ensures that the type of the value is consistent with the type of the target property. If not, then the code won't compile. I always favour static type checking where possible, it means that there's no chance that a mistake you make will only reveal itself when a particular set of condition are met (ie. when a particular code path is executed) at runtime - instead the error is right in your face in the IDE, not even letting you try to run it!

Which makes the next part somewhat unfortunate. The "propertyIdentifier" must be:

  1. A simple lambda expression..
  2. .. that identifies a property getter which has a corresponding setter (though it's fine for that setter to be private)..
  3. .. where neither the getter nor setter have a Bridge [Name] / [Template] / [Ignore] / etc.. attribute on it..

If any of these conditions are not met then the "CtorSet" method will throw an exception. But you might not find out until runtime because C#'s type system is not strong enough to describe all of these requirements.

The good news, though, is that while the C# type system itself isn't powerful enough, with Visual Studio 2015 it's possible to write a Roslyn Analyser that can pick up any invalid propertyRetriever before run time, so that errors will be thrown right in your face without you ever executing the code. The even better news is that such an analyser is included in the NuGet package! But let's not get ahead of ourselves, let me finish describing what this new method actually does first..

If it's not apparent from looking at the example code above, "CtorSet" is doing some magic. It's doing some basic sort of reflection in JavaScript to work out how to identify and set the target property. Bridge won't support reflection until v2 but my code does an approximation where it sniffs about in the JavaScript representation of the "propertyIdentifier" and gets a hold of the setter. Once it has done the work to identify the setter for a given "T" and "propertyIdentifier" combination, it saves it away in an internal cache - while we can't control and performance-tune JavaScript in quite the same way that we can with the CLR, it doesn't mean that we should do the same potentially-complicated work over and over again if we don't need to!

Another thing to note, if you haven't already spotted it: "CtorSet" will call private setters. This has the potential to be disastrous, if it could be called without restrictions, since it could change the data on types that should be able to give the appearance of immutability (ie. classes that set their state in their constructor and have private-only setters.. the pedantic may wish to argue that classes with private setters should not be considered strictly immutable because private functions could change those property values, but it's entirely possible to have classes that have the attribute of being Observational Immutability in this manner, and that's all I'm really interested in).

So there are two fail-safes built in. Firstly, the type constraint on "CtorSet" means that the target must implement the IAmImmutable interface. This is completely empty and so there is no burden on the class that implements it, it merely exists as an identifier that the current type should be allowed to work with "CtorSet".

The second protection is that once "CtorSet" has been called for a particular target instance and a particular property, that property's value is "locked" - meaning that a subsequent call to "CtorSet" for the same instance and property will result in an exception being thrown. This prevents the situation from occurring where an EmployeeDetails is initialised using "CtorSet" in its constructor but then gets manipulated externally via further calls to "CtorSet". Since the EmployeeDetails properties are all set in its constructor using "CtorSet", no-one can change them later with another call to "CtorSet". (This is actually something else that is picked up by the analyser - "CtorSet" may only be called from within constructor - so if you're using this library within Visual Studio 2015 then you wouldn't have to worry about "CtorSet" being called from elsewhere, but if you're not using VS 2015 then this extra runtime protection may be reassuring).

Now that "CtorSet" is explained, I can get to the next good bit. I have another extension method:

public T With<T, TPropertyValue>(
  this T source,
  Func<T, TPropertyValue> propertyIdentifier,
  TPropertyValue value)
    with T : IAmImmutable

This works in a similar manner to "CtorSet" but, instead of setting a property value on the current instance, it will clone the target instance then update the property on that instance and then return that instance. Unless the new property value is the same as the current one, in which case this work will be bypassed and the current instance will be returned unaltered. As with "CtorSet", null values are not allowed and will return in an ArgumentNullException being thrown.

With this method, having specific "With" methods on classes is not required. Continuing with the EmployeeDetails class from the example above, if we have:

var employee = new EmployeeDetails(
  "John Smith",
  new DateTime(2014, 9, 3),
  null
);

.. and we then discover that his start date was recorded incorrectly, then this instance of the record could be replaced by calling:

employee = employee.With(_ => _.StartDate, new DateTime(2014, 9, 2));

And, just to illustrate that if-value-is-the-same-return-instance-immediately logic, if we then did the following:

var employeeUpdatedAgain= employee.With(_ => _.StartDate, new DateTime(2014, 9, 2));

.. then we could use referential equality to determine whether any change was made -

// This will be false because the "With" call specified a StartDate value that was
// the same as the StartDate value that the employee reference already had
var wasAnyChangeMade = (employeeUpdatedAgain != employee);

Bonus features

So, in this library, there are the "CtorSet" and "With" extensions methods and there is an Optional type -

public struct Optional<T> : IEquatable<Optional<T>>
{
  public static Optional<T> Missing { get; }

  public bool IsDefined { get; }
  public T Value { get { return this.value; } }
  public T GetValueOrDefault(T defaultValue);

  public static implicit operator Optional<T>(T value);
}

This has a convenience static function -

public static class Optional
{
  public static Optional<T> For<T>(T value)
  {
    return value;
  }
}

.. which makes it easier any time that you explicitly need to create an Optional<> wrapper for a value. It lets you take advantage of C#'s type inference to save yourself from having to write out the type name yourself. For example, instead of writing something like

DoSomething(new Optional<string>("Hello!"));

.. you could just write

DoSomething(Optional.For("Hello!"));

.. and type inference will know that the Optional's type is a string.

However, this is often unnecessary due to Optional's implicit operator from "T" to Optional<T>. If you have a function

public void DoSomething(Optional<string> value)
{
  // Do.. SOMETHING

.. then you can call it with any of the following:

// The really-explicit way
DoSomething(new Optional<string>("Hello!"));

// The rely-on-type-inference way
DoSomething(Optional.For("Hello!"));

// The rely-on-Optional's-implicit-operator way
DoSomething("Hello!");

There is also an immutable collection type; the NonNullList<T>. This has a very basic interface -

public sealed class NonNullList<T> : IEnumerable<T>
{
  public static NonNullList<T> Empty { get; }

  public int Count { get; }
  public T this[int index] { get; }
  public NonNullList<T> SetValue(int index, T value);
  public NonNullList<T> Insert(T item);
}

.. and it comes with a similar convenience static function -

public static class NonNullList
{
    public static NonNullList<T> Of<T>(params T[] values);
}

The reason for this type is that it's so common to need collections of values but there is nothing immediately available in Bridge that allows me to do this while maintaining guarantees about non-null values and immutability.

I thought about using the Facebook Immutable-Js library but..

  1. It's a further dependency
  2. I really wanted to continue the do-not-allow-null philosophy that I use with "CtorSet" and "With"

I actually considered calling the "NonNullList" type the "NonNullImmutableList" but "NonNull" felt redundant when I was trying to encourage non-null-by-default and "Immutable" felt redundant since immutability is what this library is for. So that left my with List<T> and that's already used! So I went with simply NonNullList<T>.

Immutable lists like this are commonly written using linked lists since, if the nodes are immutable, then sections of the list can often be shared between multiple lists - so, if you have a list with three items in it and you call "Insert" to create a new list with four items that has the new item as the new first first item in the linked list then the following three items will be the same three node instances that existed in the original list. This reuse of data is a way to make immutable types more efficient than the naive copy-the-entire-list-and-then-manipulate-the-new-version approach would be. I'm 99% sure that this is what the Facebook library uses for the simple list type and it's something I wrote about doing in C# a few years ago if you want to read more (see "Persistent Immutable Lists").

The reason that I mention this is to try to explain why the NonNullList interface is so minimal - there are no Add, InsertAt, etc.. functions. The cheapest operations to do to this structure are to add a new item at the start of the list and to iterate through the items from the start, so I started off with only those facilities initially. Then I added a getter (which is an O(n) operation, rather than the O(1) that you get with a standard array) and a setter (which is similarly O(n) in cost, compared to O(1) for an array) because they are useful in many situations. In the future I might expand this class to include more List-like functions, but I haven't for now.

Just to make this point clear one more time: NonNullList<T> functions will throw exceptions if null values are ever specified - all values should be non-null and the type of "T" should be an Optional if null values are required (in which case none of the actual elements of the set will be null since they will all be Optional instances and Optional is a struct).

To make it easier to work with properties that are collections of items, there is another "With" method signature:

public T With<T, TPropertyElement>(
  this T source,
  Func<T, NonNullList<TPropertyElement>> propertyIdentifier,
  int index,
  TPropertyElement value)

So, if you had a class like this -

public class Something : IAmImmutable
{
  public Something(int id, NonNullList<string> items)
  {
    this.CtorSet(_ => _.Id, id);
    this.CtorSet(_ => _.Items, items);
  }
  public int Id { get; private set; }
  public NonNullList<string> Items { get; private set; }
}

.. and an instance of one created with:

var s = new Something(1, NonNullList.Of("ZERO", "One"));

.. and you then wanted to change the casing of that second item, then you could do so with:

s = s.With(_ => _.Items, 1, "ONE");

If you specified an invalid index then it would fail at runtime, as it would if you tried to pass a null value. If you tried to specify a value that was of an incompatible type then you would get a compile error as the method signature ensures that the specified value matches the NonNullList<T>'s item type.

Getting hold of the library

If this has piqued your interest then you can get the library from NuGet - it's called "ProductiveRage.Immutable". It should work fine with Visual Studio 2013 but I would recommend that you use 2015, since then the analysers that are part of the NuGet package will be installed and enabled as well. The analysers confirm that every "property retriever" argument is always a simple lambda, such as

_ => _.Name

.. and ensures that "Name" is a property that both "CtorSet" and "With" are able to use in their manipulations*. If this is not the case, then you will get a descriptive error message explaining why.

* (For example, properties may not be used whose getter or setter has a Bridge [Name], [Template] or [Ignore] attribute attached to it).

One think to be aware of with using Visual Studio 2015 with Bridge.Net, though, is that Bridge does not yet support C# 6 syntax. So don't get carried away with the wonderful new capabilities (like my beloved nameof). Support for this new syntax is, I believe, coming in Bridge v2..

If you want to look at the actual code then feel free to check it out at github.com/ProductiveRage/Bridge.Immutable. That's got the library code itself as well as the analysers and the unit tests for the analysers. It's the first time that I've tried to produce a full, polished analyser and I had fun! As well as a few speed bumps.. (possibly a topic for another day).

While the library, as delivered through the NuGet package, should work fine for both VS 2013 and VS 2015, building the solution yourself requires VS 2015 Update 1.

Is this proven and battle-hardened?

No.

At this point in time, this is mostly still a concept that I wanted to try out. I think that what I've got is reliable and quite nicely rounded - I've tried to break it and haven't been able to yet. And I intend to use it in some projects that I'm working on. However, at this moment in time, you might want to consider it somewhat experimental. Or you could just be brave and starting using it all over the place to see if it fits in with your world view regarding how you should write C# :)

Is "IAmImmutable" really necessary?

If you've really been paying attention to all this, you might have noticed that I said earlier that the IAmImmutable interface is used to identify types that have been designed to work with "CtorSet", to ensure that you can't call "CtorSet" on references that weren't expecting it and whose should-be-private internals you could then meddle with. Well, it would be a reasonable question to ask:

Since there is an analyser to ensure that "CtorSet" is only called from within a constructor, surely IAmImmutable is unnecessary because it would not be possible to call "CtorSet" from places where it shouldn't be?

I have given this some thought and have decided (for now, at least) to stick with the IAmImmutable marker interface for two reasons:

  1. If you're writing code where the analyser is not being used (such as in Visual Studio versions before 2015) then it makes it harder to write code that could change private state where it should not be possible
  2. It avoids polluting the auto-complete matches by only allowing "CtorSet" and "With" to be called against any type, even where it's not applicable (such as on the string class, for example)

The first point refers to the fallback defense mechanism that will not allow properties to have their value set more than once using "CtorSet", attempting to do so will result in a runtime error. If a class has all of its properties set using "CtorSet" within its constructor then any external, subsequent "CtorSet" call will fail. Having to implement the IAmImmutable interface when writing immutable types hopefully acts as a reminder to do this. Without this extra protection (and without the analyser), your code could contain "CtorSet" calls that manipulate private state in classes that have no idea what's hit them!

Meanwhile, the second just feels like a good practice so that "CtorSet" and "With" don't crop up over and over again on types that you would not want to use them with.

If anyone really wanted the IAmImmutable-requirement to be relaxed (which would allow the immutable types to be written in an even more succinct manner, since they wouldn't need to implement that interface) then I would definitely be up for a debate.

Posted at 22:22

Comments

React (and Flux) with Bridge.net - Redux

Earlier in the year I wrote about using Bridge.net to write browser-based applications using React. Well, now, I'd like to present an update to that. I've changed how the base Component class ties into the React library (this is a class that may be derived from in order to create custom React components) - it now supports "SetState" - and I've added an alternative base class; the StatelessComponent, which will allow the writing of component classes that will operate as stateless components, as introduced by React 0.14. I've also improved how the components appear when viewed in the React Dev Tools browser extension and I've tied it into the latest, just-released version of Bridge (1.10) that has fixed a lot of bugs.

If you're the sort of person who likes to jump straight to the end of a book to see how it ends, then you can find the code on in my GitHub "Bridge.React" repo or you can add it to a Bridge project through NuGet (Bridge.React). But if you want to find out more of the details then keep reading! I'm not going to presume any prior knowledge from my previous post - so if you've read that, then I'm afraid I'm going to re-tread some of the same ground - however, I imagine that I don't have that many dedicated followers, so figure it makes more sense to make this entry nicely self-contained :)

As simple as could be

In the past, I've also written about writing bindings for TypeScript (which is a language I liked.. but not as much as C#) and bindings for DuoCode (which is a project that seemed to have promise until they spent so longer thinking about their pricing model that I gave up on them) as well as a couple of posts about Bridge - and, often, I've got quite technical about how the bindings work under the hood. Today, though, I'm just going to deal with how to use the bindings. I'm happy that they're finally fully-populated and I've tried to make an effort to make them easy to consume, so let's just stick to getting Bridge apps talking to React and not worry about the magic behind the scenes!

I'm going to assume that you're familiar with React - though I won't be going into too much depth on it, so if you're not an expert then it shouldn't be any problem. I'm not going to assume that you have tried out Bridge yet, because it's so easy to presume that you haven't that it won't take us long to start from scratch!

Hello world

So, let's really start from the basics. You need to create a new solution in Visual Studio - choose a C# Class Library. Now go to References / Manage NuGet Packages, search for "Bridge.React" online and install the package. This will automatically pull in the Bridge package as a dependency, and this sets up a "demo.html" file under the "Bridge/www" folder to make getting started as frictionless as possible. That file has the following content:

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Bridge BridgeReactBlogPost</title>
    <script src="../output/bridge.js"></script>
    <script src="../output/BridgeReactBlogPost.js"></script>
</head>
<body>
    <!--
        Right-Click on this file
        and select "View in Browser"
    -->
</body>
</html>

Note that the title and the JavaScript filename are taken from the project name. So the file above mentions "BridgeReactBlogPost" because that's the name of the project that I'm creating myself alongside writing this post (just to ensure that I don't miss any steps or present any dodgy demonstration code!).

We need to add a few more items now - the React library JavaScript, the Bridge.React JavaScript and an element for React to render inside. So change demo.html to something like the following:

<!DOCTYPE html>

<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Bridge BridgeReactBlogPost</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
    <script src="../output/bridge.js"></script>
    <script src="../output/bridge.react.js"></script>
    <script src="../output/BridgeReactBlogPost.js"></script>
</head>
<body>
    <div id="main" />
</body>
</html>

(Aside: If you want to, then you can add the line

"combineScripts": true

to your bridge.json file, which will cause ALL of the project JavaScript files to be built into a single file - including "bridge.js" and "bridge.react.js" - so, if you used this option, you would only need to include a single JavaScript file. In this example, it would be just "../output/BridgeReactBlogPost.js").

Now change the "Class1.cs" file (that was created automatically when you requested the new "Class Library" project) thusly:

using Bridge.Html5;
using Bridge.React;

namespace BridgeReactBlogPost
{
  public class Class1
  {
    [Ready]
    public static void Main()
    {
      React.Render(
        DOM.Div(
          new Attributes { ClassName = "wrapper" },
          "Hiya!"
        ),
        Document.GetElementById("main")
      );
    }
  }
}

.. and then right-click on demo.html, click "View in Browser" and you should be greeted by some React-rendered content. Good start!

Update (2nd December 2015): I originally showed a non-static method above with a [Ready] attribute on it - this worked in earlier versions of Bridge but does not work any longer. In the examples in this post, using an instance method with the [Ready] attribute will result in the method NOT being called at DOM ready (it will appear to fail silently by doing no work but showing no warnings). Don't make my mistake, make [Ready] methods static!

Now, let's be slightly more ambitious -

[Ready]
public static void Main()
{
  React.Render(
    DOM.Div(new Attributes { ClassName = "wrapper" },
      DOM.Input(new InputAttributes
      {
        OnChange = e => Window.Alert(e.CurrentTarget.Value),
        MaxLength = 3
      })
    ),
    Document.GetElementById("main")
  );
}

Re-build then use "View in Browser" again. Now each change to the input box is thrown back in your face in an alert. The type of "e.CurrentTarget" is "InputElement" and so there is a string "Value" property available. And the "InputAttributes" class allows the setting of all of the properties that are specific to an InputElement, such as "MaxLength". This is one of the great things about using a type system to document your API - you use types (such as requiring an InputAttributes instance when DOM.Input is called) to inform the user of the API; what can and can't be done. And, while I've got a lot of respect for the people maintaining the DefinitelyTyped TypeScript type definitions, you don't get as much detail in their React bindings as are available here!

In fairness, I should really give credit where it's due here - the "InputElement" type comes from the Bridge.Html5 namespace, so I haven't had to write all of those definitions myself. And the "InputAttributes" class was based upon the InputElement's source code; I only had to remove read-only properties (for example, the html "input" element has a "valueAsNumber" property - only applicable to input elements with type "number" - that is read-only and so it would not make sense for this to be settable as a React attribute). I also had to remove some unsupported functionality (for example, checkbox input elements support an "indeterminate" flag in browsers but this is not supported by React).

All of the element factory methods in React ("div", "span", "input", etc..) have corresponding methods in the bindings, with types that express any additional properties that should be available - eg. we have

ReactElement TD(
  TableCellAttributes properties,
  params Any<ReactElement, string>[] children
);

where the "TableCellAttributes" introduces additional properties such as "int ColSpan" and "int RowSpan" (note that the bindings all use pascal-cased function and type names since this is what is more commonly seen in C# code - where the functions are translated into JavaScript they will automatically use the camel-cased JavaScript names, so "Div" becomes "div", for example).

Creating your own components

But this is the boring stuff - as soon as you start using React, you want to create your own components!

React 0.14 introduced a concept, the "Stateless Component". In native JavaScript, this is just a function that takes a props reference and returns a React element. But to make it feel more natural in C#, the bindings have a base class which can effectively become a Stateless Component - eg.

public class MyLabel : StatelessComponent<MyLabel.Props>
{
  public MyLabel(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Label(
      new LabelAttributes { ClassName = props.ClassName },
      props.Value
    );
  }

  public class Props
  {
    public string Value;
    public string ClassName;
  }
}

The "StatelessComponent" base class takes a generic type parameter that describe the "props" reference type. Then, when "Render" is called, the "props" reference will be populated and ready to use within Render. If any other functions are declared within the class, they may be called from Render as you might expect (see further down). So we are able to write very simple custom components that React will treat as these special Stateless Components - about which, Facebook say:

In the future, we'll also be able to make performance optimizations specific to these components

Creating one of these components is as easy as:

React.Render(
  new MyLabel(new MyLabel.Props { ClassName = "wrapper", Value = "Hi!" }),
  Document.GetElementById("main")
);

It is important to note, however, that - due to the way that React creates components - the constructor of these classes must always be a no-op (it won't actually be called when React prepares the component) and the only data that the class can have passed in must be described in the props data. If you tried to do something like the following then it won't work -

public class MyLabel : StatelessComponent<MyLabel.Props>
{
  private readonly int _index;
  public MyLabel(Props props, int index) : base(props)
  {
    // THIS WON'T WORK - the constructor is not processed
    _index = index;
  }

  public override ReactElement Render()
  {
    return DOM.Label(
      new LabelAttributes { ClassName = props.ClassName },
      props.Value + " (index: " + _index + ")"
    );
  }

  public class Props
  {
    public string Value;
    public string ClassName;
  }
}

You can use instance members if you want to, you just can't rely on them being set in the constructor because the constructor is never called. Side note: I'm thinking about trying to write a C# Analyser to accompany these bindings so that any rules like this can be pointed out by the compiler, rather than you just having to remember them.

public class MyLabel : StatelessComponent<MyLabel.Props>
{
  private int _index;
  public MyLabel(Props props) : base(props) { }

  public override ReactElement Render()
  {
    // Accessing instance fields and methods is fine, so long as it
    // isn't done in the constructor
    SetIndex();
    return DOM.Label(
      new LabelAttributes { ClassName = props.ClassName },
      props.Value + " (index: " + _index + ")"
    );
  }

  private void SetIndex()
  {
      _index = MagicStaticIndexGenerator.GetNext();
  }

  public class Props
  {
    public string Value;
    public string ClassName;
  }
}

You can also create custom components that have child elements. Just like "DOM.Div" takes an attributes reference (its "Props", essentially) and then an array of child elements, the StatelessComponent class takes a params array after that first "props" argument.

This array has elements of type "Any<ReactElement, string>", which means that it can be the result of a React factory method (such as "Div") or it can be a string, so that text elements can be easily rendered. Or it can be any class that derives from StatelessComponent as StatelessComponent has an implicit cast operator to ReactElement.

(Note: There used to be a ReactElementOrText class mentioned here but it didn't offer any benefit over Bridge's generic Any<,> class, so I've changed the NuGet package - as of 1.3.0 / 27th September 2015 - and have updated this post accordingly).

So, we could create a simple "wrapper" component that renders a Div with a class and some children -

public class MyWrapper : StatelessComponent<MyWrapper.Props>
{
  public MyWrapper(Props props, params Any<ReactElement, string>[] children)
    : base(props, children) { }

  public override ReactElement Render()
  {
    return DOM.Div(
      new Attributes { ClassName = props.ClassName },
      Children
    );
  }

  public class Props
  {
    public string ClassName;
  }
}

And render it like this:

React.Render(
  new MyWrapper(new MyWrapper.Props { ClassName = "wrapper" },
    DOM.Span(null, "Child1"),
    DOM.Span(null, "Child2"),
    DOM.Span(null, "Child3")
  ),
  Document.GetElementById("main")
);

or even just like:

React.Render(
  new MyWrapper(new MyWrapper.Props { ClassName = "wrapper" },
    "Child1",
    "Child2",
    "Child3"
  ),
  Document.GetElementById("main")
);

The "Children" property accessed within MyWrapper is exposed through StatelessComponent and will echo back the child elements passed into the constructor when the component instance was declared. If there were no children specified then it will be an empty array.

This brings us on to the next topic - Keys for dynamic children. To aid React's reconciliation process in cases where dynamic children elements are specified, you should specify Key values for each item. Each Key should be consistent and unique within the parent component (for more details, read the "Keys / Reconciliation" section from the Facebook docs).

If you were declaring React components in vanilla JavaScript, then this would be as easy as including a "key" value in the props object. Using these Bridge bindings, it's almost as simple - if your component needs to support an optional "Key" property then its Props class should include a "Key" property. And that's all that's required! You don't need to set anything to that Key inside your component, you merely need to allow it to be set on the props. React will accept numeric or string keys, so I would recommend that you declare the "Key" property as either an int or a string or as an Any<int, string>, which is built-in Bridge class that allows either of the value types to be used. To illustrate:

public class MyListItem : StatelessComponent<MyListItem.Props>
{
  public MyListItem(Props props) : base(props) { }

  public override ReactElement Render()
  {
    return DOM.Li(null, props.Value);
  }

  public class Props
  {
    public Any<int, string> Key;
    public string Value;
  }
}

Note: In the earlier examples, the "Child{x}" elements were fixed at compile time and so didn't need Key properties to be set, but if you were displaying a list of search results that were based on data from an api call, for example, then these elements would NOT be fixed at compile time and so you should specify unique Key values for them.

"Full" Components

So far, I've only talked about stateless components, which are like a slimmed-down version of full React components. But sometimes you need a stateful component, or one that supports the full React lifecycle.

For these times, there is another base class - simply called Component. This has two generic type parameters, one for the "props" data and for "state". However, the constructor signature is the same as the StatelessComponent; it takes a props reference and then any children element that the component instance has. The state reference is controlled by the two React component lifecycle functions "GetInitialState" and "SetState". "GetInitialState" is called when the component is first created and "SetState" can be used to not only update the internal "state" reference but also request that the component re-render.

The most basic example would be something like this:

// Note: I've not even declared a class fortthe State, I've just used
// "string" since the state in this class is just a string value. But
// that's because I'm lazy, the state was more complicated then it
// could be a separate class, just like Props.
public class StatefulControlledTextInput
  : Component<StatefulControlledTextInput.Props, string>
{
  public StatefulControlledTextInput(Props props) : base(props) { }

  protected override string GetInitialState() { return ""; }

  public override ReactElement Render()
  {
    return DOM.Input(new InputAttributes
    {
      ClassName = props.ClassName,
      Type = InputType.Text,
      Value = state,
      OnChange = ev => SetState(ev.CurrentTarget.Value)
    });
  }

  public class Props
  {
    public string ClassName;
  }
}

Each time the input's value is changed, the component calls its own SetState function so that it can re-render with the new value (there's a good Facebook summary article if you've forgotten the difference between "controlled" and "uncontrolled" components; the gist is the controlled components only raise events when the user requests that their values change, they won't be redrawn unless React cause them to redraw).

This isn't all that the Component class allows, though, it has support for the other React component lifecycle methods - for example, sometimes the "OnChange" event of a text input is raised when the content hasn't really changed (if you put focus in a text input and [Ctrl]-[C] / copy whatever value is in it and then [Ctrl]-[V] / paste that value straight back in, the OnChange event will be raised even though the new value is exactly the same as the old value). You might consider this redraw to be unacceptable. In which case, you could take advantage of the "ShouldComponentUpdate" function like this:

public class StatefulControlledTextInput
  : Component<StatefulControlledTextInput.Props, string>
{
  public StatefulControlledTextInput(Props props) : base(props) { }

  protected override string GetInitialState() { return ""; }

  protected override bool ShouldComponentUpdate(
    StatefulControlledTextInput.Props nextProps,
    string nextState)
  {
    return (props != nextProps) || (state != nextState);
  }

  public override ReactElement Render()
  {
    return DOM.Input(new InputAttributes
    {
      ClassName = props.ClassName,
      Type = InputType.Text,
      Value = state,
      OnChange = ev => SetState(ev.CurrentTarget.Value)
    });
  }

  public class Props
  {
    public string ClassName;
  }
}

Now, in the cases where the input's value doesn't really change, the component's "update" will be bypassed.

Clearly, this is a trivial example, but it demonstrates how you could do something more complicated along these lines. All of the other functions "ComponentDidMount", "ComponentDidUpdate", "ComponentWillMount", "ComponentWillReceiveProps", "ComponentWillUnmount" and "ComponentWillUpdate" are also supported.

And, of course, the Component base class has the same "Children" integration that StatelessComponent has and the same support for specifying a "Key" props value.

There is one little oddity to be aware of, though: In React, "setState" has (in my opinion) a slightly odd behaviour in that it will accept a "partial state value" that it will then merge with the current state reference. So if you had a MyComponentState class with properties "Value1" and "Value2" then you could, in vanilla JavaScript React, call setState({ Value1: whatever }) and it would take that "Value1" and overwrite the current "Value1" in the current state reference, leaving any existing "Value2" untouched. In these bindings, you must specify an entire State reference and this merging does not occur - the old State reference is replaced entirely by the new. This is largely because the "SetState" function in the bindings takes a full "State" class reference (C# doesn't really have a concept of a part-of-this-class representation) but it's also because I think that it's clearer this way; I think that you should be explicit about what you're setting State to and having it be a-bit-of-what-was-there-before and a-bit-of-something-new is not as clear (if you ask me) as a complete here-is-the-new-state reference.

More to come

In React, it is strongly recommended that props and state be considered to be immutable references. In the examples here I've used immutability-by-convention; the "props" classes have not actually been immutable types. I'm intending to write a follow-up article or two because there is more that I want to explore, such as how to use these bindings to write React apps in a "Flux"-like manner and how to take more advantage of genuinely immutable types. But, hopefully, this has been a nice enough introduction into the bindings and got you thinking about trying to use C# to write some React apps! Because, if you're aiming to write a web application in a "Single Page Application" style, if your application is of any serious complexity then you're going to end up with quite a lot of code - and, while I have a real soft spot for JavaScript, if it comes to maintaining a large app that's written in JavaScript or that's written in C# then I know which way I would lean! Thank goodness Bridge.net has come along and let us combine JavaScript frameworks with C# :)

Posted at 23:29

Comments

Strongly-typed React (with Bridge.net)

A few weeks ago, I wrote about using React with Bridge.net. I described that I'd only written the bare minimum of bindings required to get my samples working - so, while I had a function for React.DOM.div -

[Name("div")]
public extern static ReactElement Div(
  HTMLAttributes properties,
  params ReactElementOrText[] children
);

The HTMLAttributes class I had written really was the bare minimum:

[Ignore]
[ObjectLiteral]
public class HTMLAttributes
{
  public string className;
}

It's time to revisit this and build up my bindings library!

A starting point

An obvious resource to work from initially is the "DefinitelyTyped" bindings that allow you to use React from TypeScript. But I'd identified a pattern that I didn't like with them in my earlier post - the type system isn't being used to as full effect as it could be. For example, in the declaration of "input" elements. Let me explain (and please bear with me, I need to go through a few steps to get to the point)..

The TypeScript bindings describe a function for creating input elements:

React.DOM.input(props: HTMLAttributes, ...children: ReactNode[]): DOMElement

For any non-TypeScripters, this is a function that takes an argument named "props" that is of type HTMLAttributes, and then 0, 1, .. n arguments of type ReactNode that are wrapped up into an array (the same principle as "params" arguments in C#). It returns a DOMElement instance.

HTMLAttributes has 115 of its own properties (such as "className", "disabled" and "itemScope" - to take three at random) and extends DOMAttributes, which has 34 more properties (such as "onChange" and "onDragStart").

The "onChange" property is a FormEventHandler, which is derived from EventHandler<FormEvent>, where EventHandler<E> is a delegate which has a single "event" argument of type "E" which returns no value. It's a callback, in other words.

This looks promising and is, on the whole, a good use of TypeScript's generics system.

However, I don't think it uses this system enough. The FormEvent (that the "onChange" property passes in the callback) is a specialisation of a SyntheticEvent type:

interface FormEvent extends SyntheticEvent { }

interface SyntheticEvent {
  bubbles: boolean;
  cancelable: boolean;
  currentTarget: EventTarget;
  defaultPrevented: boolean;
  eventPhase: number;
  isTrusted: boolean;
  nativeEvent: Event;
  preventDefault(): void;
  stopPropagation(): void;
  target: EventTarget;
  timeStamp: Date;
  type: string;
}

(The EventTarget, which is what the "target" property is an instance of, is a DOM concept and is not a type defined by the React bindings, it just means that it is one of the DOM elements that are able to raise events).

The problem I have is that if we write code such as

React.DOM.input({
  value: "hi"
  onChange: e => { alert(e.target.value); }
})

Then we'll get a TypeScript compile error because "e.target" is only known to be of type EventTarget, it is not known to be an input element and so it is not known to have a "value" property. But we're specifying this "onChange" property while declaring an input element.. the type system should know that the "e.target" reference will be an input!

In fact, in TypeScript, we actually have to skirt around the type system to make it work:

// "<any>" means cast the "e.target" reference to the magic type "any", which
// is like "dynamic" in C# - you can specify any property or method and the
// compiler will assume you know what you're doing and allow it (resulting
// in a runtime exception if you get it wrong)
React.DOM.input({
  value: "hi"
  onChange: e => { alert((<any>e.target).value); }
})

In my React bindings for Bridge I improved this by defining an InputAttributes type:

[Ignore]
[ObjectLiteral]
public class InputAttributes : HTMLAttributes
{
  public Action<FormEvent<InputEventTarget>> onChange;
  public string value;
}

And having a generic FormEvent<T> which inherits from FormEvent -

[Ignore]
public class FormEvent<T> : FormEvent where T : EventTarget
{
  public new T target;
}

This means that the "target" property can be typed more specifically. And so, when you're writing this sort of code in C# with Bridge.net, you can write things like:

// No nasty casts required! The type system knows that "e.target" is an
// "InputEventTarget" and therefore knows that it has a "value" property
// that is a string.
DOM.Input(new InputAttributes
{
  value = "hi",
  onChange = e => Global.Alert(e.target.value)
})

This is great stuff! And I'm not changing how React works in any way, I'm just changing how we interpret the data that React is communicating; the event reference in the input's "onChange" callback has always had a "target" which had a "value" property, it's just that the TypeScript bindings don't tell us this through the type system.

So that's all good.. but it did require me to write more code for the bindings. The InputEventTarget class, for example, is one I had to define:

[Ignore]
public class InputEventTarget : EventTarget
{
  public string value;
}

And I've already mentioned having to define the FormEvent<T> and InputAttributes classes..

What I'm saying is that these improvements do not come for free, they required some analysis and some further effort putting into the bindings (which is not to take anything away from DefinitelyTyped, by the way - I'm a big fan of the work in that repository and I'm very glad that it's available, both for TypeScript / React work I've done in the past and to use as a starting point for Bridge bindings).

Seeing how these more focussed / specific classes can improve things, I come to my second problem with the TypeScript bindings..

Why must the HTMLAttributes have almost 150 properties??

The place that I wanted to start in extending my (very minimal) bindings was in fleshing out the HTMLAttributes class. Considering that it had only a single property ("className") so far, and that it would be used by so many element types, that seemed like a reasonable plan. But looking at the TypeScript binding, I felt like I was drowning in properties.. I realised that I wasn't familiar with everything that appeared in html5, but I was astonished by how many options there were - and convinced that they couldn't all be applicable to all elements types. So I picked one at random, of those that stood out as being completely unfamiliar to me: "download".

w3schools has this to say about the HTML <a> download Attribute:

The download attribute is new for the <a> tag in HTML5.

and

The download attribute specifies that the target will be downloaded when a user clicks on the hyperlink.
This attribute is only used if the href attribute is set.
The value of the attribute will be the name of the downloaded file. There are no restrictions on allowed values, and the browser will automatically detect the correct file extension and add it to the file (.img, .pdf, .txt, .html, etc.).

So it appears that this attribute is only applicable to anchor tags. Therefore, it would make more sense to not have a "React.DOM.a" function such as:

[Name("a")]
public extern static ReactElement A(
  HTMLAttributes properties,
  params ReactElementOrText[] children
);

and, like the "input" function, to be more specific and create a new "attributes" type. So the function would be better as:

[Name("a")]
public extern static ReactElement A(
  AnchorAttributes properties,
  params ReactElementOrText[] children
);

and the new type would be something like:

[Ignore]
[ObjectLiteral]
public class AnchorAttributes : HTMLAttributes
{
  public string download;
}

This would allow the "download" property to be pulled out of HTMLAttributes (so that it couldn't be a applied to a "div", for example, where it has no meaning).

So one down! Many, many more to go..

Some properties are applicable to multiple element types, but these elements may not have anything else in common. As such, I think it would be more sensible to duplicate some properties in multiple attributes classes, rather than trying to come up with a complicated inheritance tree that tries to avoid any repeating of properties, at the cost of the complexities that inheritance can bring. For example, "href" is a valid attribute for both "a" and "link" tags, but these elements do not otherwise have much in common - so it might be better to have completely distinct classes

[Ignore]
[ObjectLiteral]
public class AnchorAttributes : HTMLAttributes
{
  public string href;
  public string download;
  // .. and other attributes specified to anchor tags
}

[Ignore]
[ObjectLiteral]
public class LinkAttributes : HTMLAttributes
{
  public string href;
  // .. and other attributes specified to link tags
}

than to try to create a base class

[Ignore]
[ObjectLiteral]
public abstract class HasHrefAttribute : HTMLAttributes
{
  public string href;
}

which AnchorAttributes and LinkAttributes could be derived from. While it might appear initially to make sense, I imagine that it will all come unstuck quite quickly and you'll end up finding yourself wanting to inherit from multiple base classes and all sorts of things that C# doesn't like. I think this is a KISS over DRY scenario (I'd rather repeat "public string href;" in a few distinct places than try to tie the classes together in some convoluted manner).

More type shenanigans

So, with more thought and planning, I think a reduced HTMLAttributes class could be written and a range of attribute classes produced that make the type system work for us. I should probably admit that I haven't actually done any of that further thought or planning yet! I feel like I've spent this month coming up with grandiose schemes and then writing about doing them rather than actually getting them done! :D

Anyway, enough about my shortcomings, there's another issue I found while looking into this "download" attribute. Thankfully, it's a minor problem that can easily be solved with the way that bindings may be written for Bridge..

There was an issue on React's GitHub repo: "Improve handling of download attribute" which says the following:

Currently, the "download" attribute is handled as a normal attribute. It would be nice if it could be treated as a boolean value attribute when its value is a boolean. ... For example,

a({href: 'thing', download: true}, 'clickme'); // => <a href="thing" download>clickme</a>

a({href: 'thing', download: 'File.pdf'}, 'clickme'); // => <a href="thing" download="File.pdf">

This indicates that

[Ignore]
[ObjectLiteral]
public class AnchorAttributes : HTMLAttributes
{
  public string href;
  public string download;
  // .. and other attributes specified to anchor tags
}

is not good enough and that "download" needs to be allowed to be a string or a boolean.

This can be worked around by introducing a new class

[Ignore]
public sealed class StringOrBoolean
{
  private StringOrBoolean() { }

  public static implicit operator StringOrBoolean(bool value)
    => new StringOrBoolean();

  public static implicit operator StringOrBoolean(string value)
    => new StringOrBoolean();
}

This looks a bit strange at first glance. But it is only be used to describe a way to pass information in a binding, that's why it's got the "Ignore" attribute on it - that means that this class will not be translated into any JavaScript by Bridge, it exists solely to tell the type system how one thing talks to another (my React with Bridge.net post talked a little bit about this attribute, and others similar to it, that are used in creating Bridge bindings - so if you want to know more, that's a good place to start).

This explains why the "value" argument used in either of the implicit operators is thrown away - it's because it's never used by the binding code! It is only so that we can use this type in the attribute class:

[Ignore]
[ObjectLiteral]
public class AnchorAttributes : HTMLAttributes
{
  public string href;
  public StringOrBoolean download;
  // .. and other attributes specified to anchor tags
}

And this allows to then write code like

DOM.a(new AnchorAttributes
{
  href: "/instructions.pdf",
  download: "My Site's Instructions.pdf"
})

or

DOM.a(new AnchorAttributes
{
  href: "/instructions.pdf",
  download: true
})

We only require this class to exist so that we can tell the type system that React is cool with us giving a string value for "download" or a boolean value.

The "ObjectLiteral" attribute on these classes means that the code

DOM.a(new AnchorAttributes
{
  href: "/instructions.pdf",
  download: true
})

is not even translated into an instantiation of a class called "AnchorAttributes", it is instead translated into a simple object literal -

// It is NOT translated into this
React.DOM.a(
  Bridge.merge(
    new Bridge.React.AnchorAttributes(),
    { name: "/instructions.pdf", download: true }
  )
)

// It IS just translated into this
React.DOM.a({ name: "/instructions.pdf", download: true })

Again, this illustrates why the "value" argument was thrown away in the StringOrBoolean implicit operator calls - because those calls do not exist in the translated JavaScript.

A nice bonus

Another thing that I like about the "ObjectLiteral" attribute that I've used on these {Whatever}Attributes classes is that the translated code only includes the properties that have been explicitly set.

This means that, unlike in the TypeScript definitions, we don't have to declare all value types as nullable. If, for example, we have an attributes class for table cells - like:

[Ignore]
[ObjectLiteral]
public class TableCellAttributes : HTMLAttributes
{
  public int colSpan;
  public int rowSpan;
}

and we have C# code like this:

DOM.td(new TableCellAttributes { colSpan = 2 }, "Hello!")

Then the resulting JavaScript is simply:

React.DOM.td({ colSpan = 2 }, "Hello!")

Note that the unspecified "rowSpan" property does not appear in the JavaScript.

If we want it to appear, then we can specify a value in the C# code -

DOM.td(new TableCellAttributes { colSpan = 2, rowSpan = 1 }, "Hello!")

That will be translated as you would expect:

React.DOM.td({ colSpan = 2, rowSpan = 1 }, "Hello!")

This has two benefits, actually, because not only do we not have to mark all of the properties as nullable (while that wouldn't be the end of the world, it's nicer - I think - to have the attribute classes have properties that match the html values as closely as possible and using simple value types does so) but it also keeps the generated JavaScript succint. Imagine the alternative, where every property was included in the JavaScript.. every time a div element was declared it would have 150 properties listed along with it. The JavaScript code would get huge, very quickly!*

* (Ok, ok, it shouldn't be 150 properties for every div since half the point of this post is that it will be much better to create attribute classes that are as specific as possible - but there would still be a lot of properties that appear in element initialisations in the JavaScript which were not present in the C# code, it's much better only having the explicitly-specified values wind up in the translated output).

A change in Bridge 1.8

I was part way through writing about how pleased I was that unspecified properties in an [ObjectLiteral]-decorated class do not appear in the generated JavaScript when I decided to upgrade to Bridge 1.8 (which was just released two days ago).. and things stopped doing what I wanted.

With version 1.8, it seems like if you have an [ObjectLiteral] class then all of the properties will be included in the JavaScript - with default values if you did not specify them explicitly. So the example above:

DOM.td(new TableCellAttributes { colSpan = 2 }, "Hello!")

would result in something like:

React.DOM.td({
    colSpan = 2,
    rowSpan = 0,
    id = null,
    className = null,
    // .. every other HTMLAttribute value here with a default value
  },
  "Hello!"
)

Which is a real pity.

The good news is that it appears to be as easy as also including an [Ignore] attribute on the type - doing so re-enables the behaviour that only includes explicitly-specified properties in the JavaScript. However, I have been unable to find authoritative information on how [ObjectLiteral] should behave and how it should behave with or without [Ignore]. I had a quick flick through the 1.8 release notes and couldn't see any mention of this being an explicit change from 1.7 to 1.8 (but, I will admit, I wasn't super thorough in that investigation).

I only came across the idea of combining [Ignore] with [ObjectLiteral] when I was looking through their source code on GitHub (open source software, ftw!) and found a few places where there are checks for one of those attributes or both of them in some places.

(I've updated the code samples in this post to illustrate what I mean - now anywhere that has [ObjectLiteral] also has [Ignore]).

I'm a little bit concerned that this may change again in the future or that I'm not using these options correctly, but I've raised a bug in their forums and they've been very good at responding to these in the past - ObjectLiteral classes generate values for all properties in 1.8 (changed from 1.7).

What's next

So.. how am I intending to progress this? Or am I going to just leave it as an interesting initial investigation, something that I've looked briefly into and then blogged about??

Well, no. Because I am actually planning to do some useful work on this! :) I'm a big fan of both React and Bridge and hope to be doing work with both of them, so moving this along is going to be a necessity as much as a nice idea to play around with. It's just a case of how to proceed - as the I-have-never-heard-of-this-new-download-attribute story goes to show, I'm not intimately familiar with every single tag and every single attribute, particular in regards to some of the less well-known html5 combinations.

Having done some research while writing this post, I think the best resource that I've found has been MDN (the Mozilla Developer Network). It seems like you can look up any tag - eg.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a

And then find details of every attribute that it has, along with compatibility information. For example, the td table cell documentation..

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td

.. mentions "colSpan" and "rowSpan", with no particular mentions of compatibility (these have existed from day one, surely, and I don't think they're going to disappear any time soon) but also mentions attributes such as "align" and "valign" and highlights them as deprecated in html 4.01 and obsolete in html 5.

I'm strongly considering scraping these MDN pages and trying to parse out the attribute names and compatibility information (probably only supporting html5, since what's the point in supporting anything older when Bridge and React are new and and so I will be using them for writing new code and taking advantage of current standards). It doesn't provide type information (like "colSpan" is numeric or "download" may be a string or a boolean), but the DefinitelyTyped definitions will go some way in helping out with that. And MDN says that its wiki documents are available under the creative commons license, so I believe that this would acceptable use of the data, so long as they are given the appropriate credit in the bindings code that I will eventually generate (which only seems fair!).

So I think that that is what will come next - trying to glean all of the information I need about the attributes specific to particular tags and then using this to produce bindings that take as much advantage of the C# type system as possible!

Unless I'm missing something and someone else can think of a better way? Anyone??

Update (8th October 2015): I've had some suggestions from a member of the Bridge.net Team on how to reuse some of their work on html5 element definitions to make this a lot easier - so hopefully I'll have an update before too long based upon this. Before I can do so, the Bridge Team are looking into some improvements, such as allowing the "CurrentTarget" property of elements to be more strongly-typed (see http://forums.bridge.net/forum/general/feature-requests/630-open-461-generic-html5-element-and-event-classes), but hopefully we'll all have an update before too long!

Posted at 23:07

Comments

React (and Flux) with Bridge.net

A couple of months ago I talked about using DuoCode to write React applications in C#. Since then I've been waiting for DuoCode to release information about their licensing and it's been a case of "in a few days" for weeks now, so I've been looking around to if there are any alternatives. A few weeks ago I tried out Bridge.net which is an open source C#-to-JavaScript translator. It's been public for about the same length of time as DuoCode and releases have been about one a month, similar to DuoCode.

Its integration with Visual Studio doesn't have a dedicated project type option and it doesn't support the debug-in-VS-when-running-in-IE facility that DuoCode has. The compiler doesn't seem to be quite as mature as DuoCode's, I've found a few bugs with it.. but I've reported them on their forum and they've addressed them all! I reported one bug in their forum and got a reply 14 minutes later saying that a fix had been pushed to GitHub - not bad service, that! :D

It currently uses something called NRefactory to parse C# but it's moving over to Roslyn soon*. It has recently acquired Saltarelle, another open source C#-to-JavaScript translator, so now has even more resources working on it. Enough introduction, though, you can find out more on their website if you want to!

* (It seems that with the release of Visual Studio 2015 and with Roslyn hitting the mainstream, Mono is another project moving over from using NRefactory to Roslyn for its C# parsing, read more from Miguel de Icaza at Roslyn and Mono - I'm excited by this since I think Roslyn is really going to open some doors for C#'s extensibility in the future; Bridge, Mono and DuoCode are all examples of this.. I've also used it for some simple code analysis in the past, see Locating TODO comments with Roslyn).

Getting started with Bridge.net

One of the nice things about DuoCode is that it made it extremely easy to get started - you can create a new DuoCode project and run it directly. I believe that the Visual Studio project system has historically been a bit of a mess so there must have been a lot of work gone into this to make it so seamless.

Bridge is a bit different, though. The simplest way to get started is to create a new Class Library project and add the Bridge.net NuGet package. This will not make it directly executable but it does add a demo.html file (under "Bridge/www") that you can browse to (either by locating it in the file system or by just right-clicking on it and selecting "View in Browser").

With DuoCode, you have the option of splitting your work over multiple projects - the "runnable" project can reference one or more other DuoCode projects and everything will still work just fine. The problem may come, however, if you want your main project to also host some .net code - you might want to create a Web API interface, for example, for the client-side code to call. But it's not possible to have a single project that translates some of its C# into JavaScript but also leaves some of it running as .net on the server.

In Bridge, I would recommend creating a standard ASP.net MVC web project and then adding one or more Bridge class libraries that copy their generated JavaScript into a location in the front end project. Bridge makes this easy as each project that pulls in the NuGet package creates a file "Bridge/bridge.json" which allows you to specify where the output JavaScript should go. (Currently, adding the NuGet package always pulls in the "getting started" folders, such as "Bridge/www", but I'm hopeful that a just-the-basics package will be available before too long - there's a forum thread I started about it on their site: Refining the NuGet package).

Working with React

I'm going to assume that you're familiar with React and, to make my life easier in writing this article as much as anything, I'm going to assume no knowledge of my DuoCode/React post. I've written before about writing React components in TypeScript and the same sort of concepts will be covered here - but, again, I'm going to assume you haven't read that and I'll start from scratch.

I'll start from the "React.render" method and work out from there. So first we need to write a binding to it. A binding is essentially a way to tell your C# at compile time about something that will be present at runtime.

To define "React.render" I'll create a class with an "Ignore" attribute on it - this instructs the translator that it does not need to generate any JavaScript from this C# class, it will be tied up to JavaScript already loaded in the browser (the assumption here, of course, is that the page that will execute the JavaScript translated from C# will also include the "React.js" library).

using Bridge.Html5;

namespace Bridge.React
{
  [Name("React")]
  [Ignore]
  public static class React
  {
    [Name("render")]
    public extern static void Render(ReactElement element, Element container);
  }
}

Any references in the C# code to this class will try to access it within the "Bridge.React" namespace, so the C# compiler thinks its fully qualified class name is "Bridge.React.React"; in the JavaScript, though, this is not the case, the class is just called "React". The Bridge.net attribute "Name" allows us to tell the translator this - so when the C# code is translated into JavaScript, any references to "Bridge.React.React" will be rewritten to simply "React".

The same is applied to the method "Render" - in my C# code, I stick to the convention of pascal-casing function names, but the React library (like much other modern JavaScript) uses camel-cased function names.

Also note that the "Render" method does not have an implementation, it is marked as "extern". This is more commonly used in C# code to access unmanaged DLL functions but the bindings to JavaScript that we're describing are a similar mechanism - no body for this method needs to be included since the method itself is implemented elsewhere (in the React library, in this case). In order to be marked as "extern", a function must be decorated with an attribute (otherwise the compiler generates warnings). It doesn't matter what attribute is used, so the presence of the "Name" attribute is good enough.

For the function's arguments, the Element type is a Bridge.net class that represents DOM elements while the ReactElement is one that we must define as a binding -

namespace Bridge.React
{
  [Ignore]
  public sealed class ReactElement
  {
    private ReactElement() { }
  }
}

This will never be explicitly instantiated, so it's a sealed class with a private constructor. It also does not need to be directly represented in the generated JavaScript, so it has an "Ignore" attribute on it too.

But, if ReactElement is never directly instantiated, how do we get instances of it? Well, there's the builtin React element creator functions (eg. "React.DOM.div", "React.DOM.span", etc..) and there are custom components. The builtin functions are nice and simple to writing bindings for, so I'll talk about them later and get to the interesting stuff..

Creating React components in Bridge.net

Since React 0.13 was released earlier this year, it has been possible to write JavaScript "classes" that may be used as React components. I write "classes" in quotes because a class is an ES6 concept but the code that transpilers emit (that take ES6 JavaScript and create equivalent code that will work on browsers that don't support ES6) is similar enough to the code generated by Bridge.net (and DuoCode) that we can use classes written in C# and rely upon the emitted JavaScript working nicely with React.. so long as a couple of rules are followed:

  1. These component classes will never be directly instantiated in code, so there should be no public constructor defined since it will never be called
  2. The way that they will be initialised is by the React library, via a "React.createElement" call - this will take the type of the component and will create some form of object based upon the component but according to its own rules (these are implementation details of the React library and should just be considered to be magic; trying to take advantage of any particular implementation detail is a good way to write a component that will break in a future version of React)
  3. The "createElement" call will also take a "props" reference, which will be set on the resulting React element - this is how a component is configured, rather than via the constructor (this "props" reference is private to the component and is guaranteed to be set as soon as the instance is created, so it's much more like "constructor dependency injection" than "property setter dependency injection")
  4. The components require a "render" method that returns a ReactElement

The surgery that React carries out to create components based upon classes is quite invasive, not only in how it new's-up an instance but also in how it investigates the "props" data. For each initialisation, it tears apart the provided props reference and creates a new object of its own devising, copying over the object properties from the original reference onto its own version.

This is problematic if the props reference you give is a class translated from C# since any methods (including property getters / setters) will be ignored by this process (React only copies properties that report true for "hasOwnProperty" and so ignores any class methods since these will be declared on the prototype of the class, not on the instance itself). The way to get around this is to wrap the props data in another object, one that has only a single field "Props", which is a reference back to the original props data - then, when React copies the properties around, this value will be migrated over without issue. The only annoyance is that this data must be unwrapped again before you can use it.

However, because I'm so good to you, I've pulled most of this together into an abstract class that you may use to derive custom component classes from -

using System;

namespace Bridge.React
{
  public abstract class Component<TProps>
  {
    public static ReactElement New<TComponent>(TProps props)
      where TComponent : Component<TProps>
    {
      if (props == null)
        throw new ArgumentNullException("props");

      return Script.Call<ReactElement>(
        "React.createElement",
        typeof(TComponent),
        new PropsWrapper { Props = props }
      );
    }

    [Name("render")]
    public abstract ReactElement Render();

    [Name("unwrappedProps")]
    protected TProps props
    {
      get { return wrappedProps.Props; }
    }

    [Name("props")]
    private readonly PropsWrapper wrappedProps = null;

    [ObjectLiteral]
    private class PropsWrapper
    {
      public TProps Props;
    }
  }
}

There is a static "New" method that is used to create a ReactElement instance based upon the derived component class' type (using the "React.createElement" function). In the C# code, you call "New" with a "props" reference of the appropriate type and you get a ReactElement back. The "appropriate type" is the TProps generic type parameter of this base class. Making this a generic class means that calling code knows what data is required to create a new element instance (ie. a TProps instance) and the derived component class has a strongly-typed (again, TProps) reference to that props data.

There is a "Render" method that must be implemented on the derived class. It has a "Name" attribute to map my C# naming convention (of pascal-cased function names) onto React's convention (of camel-cased function names).

You can also see some messing about with the props data - the call to "React.createElement" uses a PropsWrapper which puts the "props" reference into a single property, as I described above. This will not be torn to shreds by React when it creates a new element. This data is then readable via the private "wrappedProps" property - since this is private to this base class, derived classes can not access it. They have to retrieve props data through the "props" property (which has type TProps, rather than PropsWrapper).

Now, there is some jiggery-pokery here, since the "wrappedProps" property has a "Name" attribute which indicates that this maps to a property called "props" in the JavaScript - but, as just described, this is a wrapper that keeps the real data safe from React's meddling. Similarly, the "props" property (which has "protected" accessibility and so is accessible by the derived type) has a "Name" attribute which maps it onto a property named "unwrappedProps" - this is not something that React has anything to do with, it's only to avoid clashing with the real "props" reference in the output JavaScript, while allowing C# code to be written that accesses a "props" property that is an unwrapped version of the props data.

Wow, that all sounds really confusing! But the upshot is that you can create a component as easily as:

using Bridge.React;

namespace BridgeExamples
{
  public class WelcomeComponent : Component<WelcomeComponent.Props>
  {
    public static ReactElement New(Props props)
    {
      return New<WelcomeComponent>(props);
    }
    private WelcomeComponent() { }

    public override ReactElement Render()
    {
      return DOM.Div(null, "Hi " + props.Name);
    }

    public class Props
    {
      public Props(string name)
      {
        Name = name;
      }
      public string Name { get; private set; }
    }
  }
}

Note that the "Render" method accesses "props.Name" directly - all of the wrapping / unwrapping is hidden away in the base class, the derived class is happily oblivious to all that PropsWrapper madness.

Also note that the constructor has been declared as private, which is important since these components should never be instantiated directly - they should only be brought into existence via that "React.createElement" function. To this end, a static "New" function is present (which calls the static "New" function on the base class).

(One more note - there's an attribute used by the Component base class that I haven't explained: "ObjectLiteral", I'll come back to this later..)

Bringing all this together, we could use this component in code such as:

React.Render(
  WelcomeComponent.New(new WelcomeComponent.Props(name: "Ted")),
  Document.GetElementById("main")
);

But before doing so, we'd better get back to the builtin React element creation functions..

Warning (July 2015): The code above will actually fail at runtime with the current version of Bridge (1.7) because of a bug I reported in their forums - however this has been fixed and will be included in the next release. I'm being optimistic and hoping that this article will be relevant in the future when this bug is just a distant memory :) Until the version after 1.7 is released, replace the line

return New<WelcomeComponent>(props);

with

return Component<WelcomeComponent.Props>.New<WelcomeComponent>(props);

and it will work fine. But in the future the less verbose version shown in the WelcomeComponent example will be safe.

Bindings for the regular DOM element functions

I skirted around the DOM functions such as React.DOM.div, React.DOM.span, etc.. earlier, so let's deal with them now.

In order to do so, I need to teach the type system a little trick. A component's "Render" method must always return a genuine ReactElement, but when specifying child elements for use in a component we must be able to provide either a ReactElement or a simple string. This is what was happening in the line from the WelcomeComponent:

return DOM.Div(null, "Hi " + props.Name);

The null value is for the attributes of the div (and is interpreted as "this div does not need any html attributes"), while the second argument is a string that is the sole child element of that div.

So we need a way to say that the child element argument value(s) for a DOM.div call may be either a ReactElement or a string. In some languages (such as TypeScript and F#), we could consider a union type, but here I'll cheat a bit and declare the "React.DOM.Div" function as:

namespace Bridge.React
{
  [Name("React.DOM")]
  [Ignore]
  public static class DOM
  {
    [Name("div")]
    public extern static ReactElement Div(
      HTMLAttributes properties,
      params ReactElementOrText[] children
    );

and then define a new ReactElementOrText type -

namespace Bridge.React
{
  [Ignore]
  public sealed class ReactElementOrText
  {
    private ReactElementOrText() { }
    [Ignore]
    public extern static implicit operator ReactElementOrText(string text);
    [Ignore]
    public extern static implicit operator ReactElementOrText(ReactElement element);
  }

This is another class with an "Ignore" attribute since it does not require any JavaScript to be generated for it, it's just to provide information to the C# compiler. It means that anywhere that a ReactElementOrText type is specified as an argument type, it is valid to provide either a ReactElement or a string. (The "Ignore" attributes on the functions are only present so that they may be identified as "extern" - as described earlier, an "extern" function must be decorated with an attribute of some kind).

The DOM class makes further of the "Name" attribute, ensuring that any accesses in C# to "Bridge.React.DOM" are replaced with just "React.DOM" in the generated JavaScript.

The final piece of the puzzle is the HTMLAttributes class -

using Bridge;

namespace Bridge.React
{
  [ObjectLiteral]
  public class HTMLAttributes
  {
    public string className;
  }
}

As you can probably tell, this is not the full-featured React interface ("className" is not the only attribute that you can add to a div!) - at this point in time, it's still early days for the bindings that I'm writing for Bridge.net / React, so I've cut some corners. You'll see further down that I've not done all of the bindings for the DOM elements either! But hopefully this article is enough to get you up and running, then you can add to it yourself as you need more. (I'll also link to a repo at the end of the post..)

HTMLAttributes is another type that we don't directly want to include in the generated JavaScript. If we have the C# line -

return DOM.Div(new HTMLAttributes { className = "welcome" }, "Hello!");

we want this to be translated into the following:

return React.DOM.div({ className = "welcome" }, "Hello!");

This is idiomatic React-calling code.

Bridge.net has support to instruct the compiler to interpret class constructors in this way; through use of the "ObjectLiteral" attribute. When a class that is decorated with this attribute has its constructor called in C#, the generated JavaScript will just use the object literal notation rather than actually creating a full class instance. Note that this means that no JavaScript will be generated for that class, so the HTMLAttributes class does not appear in the JavaScript at any point.

We saw this "ObjectLiteral" attribute used earlier, on the Component base class - it was used for the wrapper around the props data. That wrapper is only used to nest the real "props" reference inside a property so that React's internals don't try to mess with it. It would be unnecessary to wrap that reference up inside a full class instance, it is more sensible for the generated JavaScript to be simply -

return React.createElement(TComponent, { props: props });

as opposed to something like

return React.createElement(
  TComponent,
  Bridge.merge(
    new Bridge.React.Component.PropsWrapper$1(TProps)(),
    { props: props }
  )
);

(which is what Bridge would emit if the PropsWrapper type did not have the "ObjectLiteral" attribute on it).

More DOM bindings..

As with the poorly-populated HTMLAttributes class, I also haven't written too many DOM element bindings yet. All I've got so far is "div", "h1", "input" and "span" - these have been enough for the sample projects I've started to experiment with integrating Bridge and React. However, the good news is that these few bindings illustrate enough principles that it should be clear how to write more as you need them.

The element creation functions that I have are as such:

using Bridge;

namespace Bridge.React
{
  [Name("React.DOM")]
  [Ignore]
  public static class DOM
  {
    [Name("div")]
    public extern static ReactElement Div(
      HTMLAttributes properties,
      params ReactElementOrText[] children
    );
    [Name("h1")]
    public extern static ReactElement H1(
      HTMLAttributes properties,
      params ReactElementOrText[] children
    );
    [Name("input")]
    public extern static ReactElement Input(
      InputAttributes properties,
      params ReactElementOrText[] children
    );
    [Name("span")]
    public extern static ReactElement Span(
      HTMLAttributes properties,
      params ReactElementOrText[] children
    );
  }
}

"Span" and "H1" are just the same as "Div".

"Input" is interesting, though..

I started by following the same basic pattern for the InputAttribute type as you would find in the React bindings for TypeScript - there is an "onChange" callback which provides a FormEvent instance, which is a type that is derived from SyntheticEvent (names taken directly from the TypeScript binding).

The big difference is that the TypeScript bindings do not expose a "target" property on FormEvent to tie the event back to the element that it relates to, even though this information is available on the React event. I've exposed this information as the "target" property on FormEvent and exposed it as a known-type using the generic FormEvent class - the InputAttributes has an "onChange" type of Action<FormEvent<InputEventTarget>> which means that the type of "target" on the FormEvent will be an InputEventTarget. This allows us to query the input's value in the onChange callback, something that is a bit awkward with the TypeScript bindings.

(This is only possible because the React model exposes this information - bindings do not include their own logic, they only describe to the Bridge compiler how to interact with an existing library).

using Bridge;

namespace Bridge.React
{
  [ObjectLiteral]
  public class InputAttributes : HTMLAttributes
  {
    public Action<FormEvent<InputEventTarget>> onChange;
    public string value;
  }

  [Ignore]
  public class FormEvent<T> : FormEvent where T : EventTarget
  {
    public new T target;
  }

  [Ignore]
  public class FormEvent : SyntheticEvent
  {
    public EventTarget target;
  }

  [Ignore]
  public class SyntheticEvent
  {
    public bool bubbles;
    public bool cancelable;
    public bool defaultPrevented;
    public Action preventDefault;
    public Action stopPropagation;
    public string type;
  }

  [Ignore]
  public class InputEventTarget : EventTarget
  {
    public string value;
  }

  [Ignore]
  public class EventTarget { }
}

There are obviously more properties that belong on the InputAttribute type (such as "onKeyDown", "onKeyPress", "onKeyUp" and many others) but for now I just wanted to write enough to prove the concept.

Flux

There's nothing that requires that you use the Flux architecture when you're using React, but I think it makes a huge amount of sense. When I was getting to grips with the React library, I found myself moving towards a similar solution before I'd read up on Flux - so when I did read about it, it was like someone had taken the vague ideas I'd had, tightened them all up and hammered out the rough edges.

The thing with it is, it really is just a set of architectural guidelines, it's not an actual library like React. It explains that you have "Stores" that manage state for the application - these Stores listen out for events that may require that they change their current state. This state is displayed using React, basically. The events that the Stores listen out for may be the result of a user interacting with the React elements or they may be raised by an API, informing the application that data that the user requested has arrived.

The piece in the middle is the "Dispatcher" and is effectively a queue that events can be pushed on (by user interactions or whatever else) and listened out for by the Stores - any events that a Store is not interested in, it ignores.

Asynchronous processes are quite easily handled in this arrangement because you can fire off an event as soon as an async request starts (in case some sort of loading spinner is desired) and then fire off another event when the data arrives (or when it times out or errors in some other way). Whatever happens, it's just events being raised and then received by interested Stores; Stores which alter their state and get React to re-render (if state changes were, in fact, required).

Using C# to write such a Dispatcher queue is really easy. Internally, it uses a C# event to make it easy to register (and then to call) as many listeners as required.

When compiled for the CLR, events are translated into IL that does all sorts of clever magic to behave well (and efficiently) in a multi-threaded environment. But here, it will be translated into JavaScript for the browser, which is single-threaded! So everything's very simple in the generated JavaScript and the C#.

using System;

namespace Bridge.React
{
  public class AppDispatcher
  {
    private event Action<DispatcherMessage> _dispatcher;

    public void Register(Action<DispatcherMessage> callback)
    {
      _dispatcher += callback;
    }

    public void HandleViewAction(IDispatcherAction action)
    {
      if (action == null)
        throw new ArgumentNullException("action");

      _dispatcher(new DispatcherMessage(MessageSourceOptions.View, action));
    }

    public void HandleServerAction(IDispatcherAction action)
    {
      if (action == null)
        throw new ArgumentNullException("action");

      _dispatcher(new DispatcherMessage(MessageSourceOptions.Server, action));
    }
  }

  public class DispatcherMessage
  {
    public DispatcherMessage(MessageSourceOptions source, IDispatcherAction action)
    {
      if ((source != MessageSourceOptions.Server) && (source != MessageSourceOptions.View))
        throw new ArgumentOutOfRangeException("source");
      if (action == null)
        throw new ArgumentNullException("action");

      Source = source;
      Action = action;
    }

    public MessageSourceOptions Source { get; private set; }
    public IDispatcherAction Action { get; private set; }
  }

  public enum MessageSourceOptions { Server, View }

  public interface IDispatcherAction { }
}

When you read about Flux events in JavaScript-based tutorials, you will see mention of "Actions" and "Action Creators". Actions will be JavaScript objects with some particular properties that describe what happened. Action Creators tend to be functions that take some arguments and generate these objects. In C#, I think it makes much more sense for Actions to be classes - that way the Action Creators are effectively just the Actions' constructors!

The Flux Architecture

The AppDispatcher I've included code for above expects actions to be classes that share a common interface: IDispatcherAction. This is an "empty interface" and is just used to identify a class as being an action (you might want to search a solution for all Dispatcher actions, for example - you could do this by locating all implementations of IDispatcherAction). I wrote about this in terms of TypeScript earlier in the year and much of the same holds true here - so read more at TypeScript classes for (React) Flux actions if this sounds interesting (or confusing).

(Each action is wrapped in a DispatcherMessage, which describes it as being either a "Server" or "View" action. A Server action would tend to be a callback from an API event, as opposed to a key press that alters a particular editable field - which would be a View action. Differentiating between the two is a common practice but is optional, so you could drop the DispatcherMessage entirely if you wanted to and have the Dispatcher only deal with IDispatcherAction implementations. The only really compelling reasons I've encountered for differentiating between the two is that you might want to skip some forms of validation for Server actions since it may be presumed that data from the server is already known to be good).

A complete example

If you want to try any of this out (particularly if you don't feel like trying to piece it all together from the various code samples in this post!) then you can find a complete sample in a Bitbucket repo: ReactBridgeDotNet.

It's a web project that follows the structure I outlined at the top of this post - an MVC project to "host" and then Bridge projects to generate JavaScript from C#; one for the React bindings and another for the logic of the app.

The app itself is very, very simple - it's just a text box that doesn't want to be empty. If you clear it then you get a validation message. Any changes that you make to the input box are communicated to the app as Dispatcher actions, each of which results in a full re-render (in a complex app, React's virtual DOM ensures that this is done in an efficient manner, but in such a small example as this it's probably impossible to tell). Meanwhile, a label alongside the input box is updated with the current time - this is done to illustrate how non-user events (such as API data-retrieved events, for example) may be dealt with in exactly the same way as user events; they go through the Dispatcher and a Store deals with applying these channels to its internal state. Have fun!

Posted at 21:17

Comments