DEV Community

David Ortinau
David Ortinau

Posted on

Managing State in Comet

Comet is a .NET experiment inspired by Flutter and Swift UI for building cross-platform apps with C#.

Comet promotes a variation of the Model-View-Update pattern popularized by The Elm Architecture, Elmish, Fabulous and others. The major parts of MVU are:

  • Model: the state of the app
  • View: the state represented to the user
  • Update: a way to update state via messages

State is (almost always) immutable and the changes flow in a single direction.

MVU diagram

Defining State

Each View has its own state and you can define this in a few ways. The most simple is to use State<T> to wrap a field in a class that implements INotifyPropertyRead.

readonly State<int> count = 0;
Enter fullscreen mode Exit fullscreen mode

Most views will probably have more complex state and you can represent that in the same way, however in order to get updates on property changes you'll want to extend BindingObject and use the get/set helpers. You can see in the Comet project template:

public class CometRide : BindingObject
{
    public int Rides
    {
        get => GetProperty<int>();
        set => SetProperty(value);
    }

    public string CometTrain
    {
        get
        {
            return "☄️".Repeat(Rides);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now within the View you can declare your state just like that simple int in the first example:

readonly State<CometRide> comet = new();
Enter fullscreen mode Exit fullscreen mode

This is equivalent to some code you may see in the older Comet samples:

[State]
readonly CometRide comet = new();
Enter fullscreen mode Exit fullscreen mode

Adding State in your View

All UI in Comet is a View, and the [Body] annotates the method that returns the view construction. This is where we can now binding our state to the UI. You "can" display the comet rides like this:

[Body]
View body()
    => new VStack {
            new Text(comet.Rides.ToString())
    };
Enter fullscreen mode Exit fullscreen mode

Each View takes a minimal set of constructor arguments, and here we pass in the state object and convert the int to a string. We can even use C# string interpolation to make this nicer.

new Text(()=> $"{comet.Rides} rides taken.")
Enter fullscreen mode Exit fullscreen mode

Notice we are now using the function lambda ()=> here. This is the optimal way to bind your state to views in Comet. Now it can reevaluate that property anytime the state of "comet" changes and apply just that property. The former method without the lambda requires the entire body of that view to be recreated.

Modifying State in your View

This is a noticeable place where Comet diverges from other MVU implementations. The message and update ceremony is streamlined. To increment the ride count in this example, let's bring in a Button view which takes 2 constructor arguments: text for the title, and an action handler.

new Button("Increment", ()=>{
    comet.Rides++;
})
Enter fullscreen mode Exit fullscreen mode

When using State<T> without a BindingObject you'll use .Value to access the value you intend to change. Using the first example: ()=> count.Value++.

This change in state will trigger the body of the view to be reevaluated. Comet uses a virtual DOM, so this is extremely fast. A dif of the view is made, and the changes are applied.

counter in iOS

Ride the Comet

There is more to be said about managing state beyond just the view, and other options such as Flux. For now this covers the basics and gets you going.

To get installed and a few other details, check out my previous setup blog.

And for a bonus, the author of Comet, James Clancey, joined the .NET MAUI Community Standup livestream last week to talk about Comet and answer questions. Enjoy!

Top comments (5)

Collapse
 
oleksandrukrainets profile image
Oleksandr Ukrainets • Edited

Hi David!
I don't understand MVU pattern and how do CRUD operation.
I did it in my example in View.
Is that way right?
How can the code be separated into layers in this pattern?
Help me please.
Thanks.

Image description

Collapse
 
n8yeung profile image
Nathan Yeung

Wow thanks for sharing this! Is this all in C#?

Collapse
 
davidortinau profile image
David Ortinau

Yes, all C#.

Because it's based on .NET MAUI you could mix in some other UI tech, but the idea is to keep it simple and use the power of C# to the fullest.

Collapse
 
jakubjenis profile image
Jakub Jenis

Cool overview. How does flux participate here? Is it an optional extension over Comet or some sort of replacement?

Collapse
 
davidortinau profile image
David Ortinau