# Stateful Components

A stateful component is a component tied to a state class that is used to keep its "state" during its lifetime.

A state is just a C# class with an empty constructor.

When a Component is first displayed on the page, i.e. the MAUI widget is added to the page visual tree, MauiReactor calls the method `OnMounted()`.

Before the component is removed from the page visual tree MauiReactor calls the `OnWillUnmount()` method.

Every time a Component is "migrated" (i.e. it is preserved between a state change) the `OnPropsChanged()` overload is called.

`OnMounted()` is the ideal point to initialize the component, for example calling web services or querying the local database to get the required information to render it in the `Render()` method.

For example, in this code we'll show an activity indicator while the Component is loading:

```csharp
public class BusyPageState
{
    public bool IsBusy { get; set; }
}

public class BusyPageComponent : Component<BusyPageState>
{
    protected override void OnMounted()
    {
        //Here is not advisable to call SetState() as the component is still not rendered yet
        State.IsBusy = true;

        //just for a test run a background task
        Task.Run(async () =>
        {
            //Simulate lengthy work
            await Task.Delay(3000);

            //finally reset state IsBusy property
            SetState(_ => _.IsBusy = false);
        });

        base.OnMounted();
    }

    public override VisualNode Render()
        => ContentPage(
            ActivityIndicator()
                .Center()
                .IsRunning(State.IsBusy)
        );
}

```

and this is the resulting app:

<figure><img src="https://877538538-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh1eh1igwiwRzrw2kbxSp%2Fuploads%2FLJia9MY0HojW9JgRpnDw%2FReactorUI_BusyDemo.gif?alt=media&#x26;token=cb4ce957-b405-45ba-9944-99af9619a88a" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Do not use constructors to pass parameters to the component, but public properties instead (take a look at the [Components Properties](https://adospace.gitbook.io/mauireactor/components/component-properties) documentation page).
{% endhint %}

## Updating the component State

When you need to update the state of your component you have to call the `SetState` method as shown above.

When you call `SetState` the component is marked as *Invalid* and MauiReactor triggers a refresh of the component. This happens following a series of steps in a fixed order

1. The component is marked as *Invalid*
2. The parent and ancestors up to the root component of the page are all marked as *Invalid*
3. MauiReactor triggers a refresh under the UI thread that creates a new Visual tree traversing the component tree
4. All the components that are *Valid* are re-used (maintained in the VisualTree) while the components marked as *Invalid* are discarded and a new version is created and its `Render` method called
5. The new component version creates a new tree of child nodes/components that are compared with the tree linked to the old version of the component
6. The old visual tree is compared to the new one: new nodes are created along with the native control (i.e. are mounted), removed nodes are eliminated along with the native control (i.e. are unmounted), and finally, nodes that are only changed (i.e. old and new nodes are of the same type) are migrated (i.e. native control is reused and its properties are updated according to properties of the new visual node)
7. In the end, the native controls are added, removed, or updated

For example, let's consider what happens when we tap the Increment button in the sample component below:

```csharp
class CounterPageState
{
    public int Counter { get; set; }
}

class CounterPage : Component<CounterPageState>
{
    public override VisualNode Render()
    => ContentPage("Counter Sample",
            VStack(spacing: 10,
                Label($"Counter: {State.Counter}")
                    .Center(),

                Button("Click To Increment", () =>
                    SetState(s => s.Counter++))
            )
            .Center()
        );
}
```

<figure><img src="https://877538538-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh1eh1igwiwRzrw2kbxSp%2Fuploads%2FodVu58HEAF90u4N1ixx9%2Fvisualtree.drawio.png?alt=media&#x26;token=af7a874d-b96e-4be0-9443-758988fc6916" alt=""><figcaption><p>All components are migrated/updated</p></figcaption></figure>

Let's now consider this revisited code:

```csharp
class CounterPageState
{
    public int Counter { get; set; }
}

class CounterPage : Component<CounterPageState>
{
    public override VisualNode Render()
        => ContentPage("Counter Sample",
            VStack(spacing: 10,
                State.Counter == 0 ? new Label($"Counter: {State.Counter}")
                    .VCenter()
                    .HCenter() : null,

                Button("Click To Increment", () =>
                    SetState(s => s.Counter++))
            )
            .Center()
        );
}
```

When the button is clicked the variable `State.Counter` is updated to 1 so the component is re-rendered and the `Label` is umounted (i.e. removed from the visual tree) and the native control is removed from the parent `VStack` Control list (i.e. de-allocated):

<figure><img src="https://877538538-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh1eh1igwiwRzrw2kbxSp%2Fuploads%2Forh9gnoFmQQCROCiPFeE%2Fvisualtree.drawio%20(1).png?alt=media&#x26;token=38886996-392c-48cd-823b-d4e2817eca93" alt=""><figcaption><p>Label is unmounted (i.e. removed from visual tree)</p></figcaption></figure>

If we click the button again, the `Label` component is found, again, in the new version of the Tree, so it's mounted and a new instance of the `Label` component is created (along with the Native control that is created and added to the parent `VStack` control list).

<figure><img src="https://877538538-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fh1eh1igwiwRzrw2kbxSp%2Fuploads%2FeO37Awt0fr17S01IH7ED%2Fvisualtree.drawio%20(2).png?alt=media&#x26;token=a81b7ac0-189f-4440-a216-92e6544f28e1" alt=""><figcaption><p>Label is mounted</p></figcaption></figure>

## Updating the state "without" triggering a refresh

Re-creating the visual tree can be expensive, especially if the component tree is deep or the components contain many nodes; but sometimes you can update the state "without" triggering a refresh of the tree resulting in a pretty good performance improvement.

For example, consider the counter sample but with a debug message added that helps trace when the component is rendered/created (line 10):

{% code lineNumbers="true" %}

```csharp
class CounterPageState
{
    public int Counter { get; set; }
}

class CounterPage : Component<CounterPageState>
{
    public override VisualNode Render()
    {
        Debug.WriteLine("Render");
        return ContentPage("Counter Sample",
            VStack(spacing: 10,
                Label($"Counter: {State.Counter}")
                    .VCenter()
                    .HCenter(),

                Button("Click To Increment", () =>
                    SetState(s => s.Counter++))
            )
            .Center()
        );
    }
}
```

{% endcode %}

Each time you click the button you should see the "Render" string output in the console of your IDE: this means, as explained, that a new Visual Tree has been created.

Now, imagine for example that we just want to update the label text and nothing else. In this case, we can take full advantage of a MauiReactor feature that lets us just update the native control *without* requiring a complete refresh.

Let's change the sample code to this:

<pre class="language-csharp" data-line-numbers><code class="lang-csharp">class CounterPageState
{
    public int Counter { get; set; }
}

class CounterPage : Component&#x3C;CounterPageState>
{
    public override VisualNode Render()
    {
        Debug.WriteLine("Render");
        return ContentPage("Counter Sample",
            VStack(spacing: 10,
<strong>                Label(()=> $"Counter: {State.Counter}")
</strong>                    .Center(),

                Button("Click To Increment", () =>
<strong>                    SetState(s => s.Counter++, invalidateComponent: false))
</strong>            )
            .Center()
        );
    }
}
</code></pre>

Notice the changes to lines 15 and 20:

15: we use an overload of the `Label()` the class that accepts a `Func<string>`\
20: secondly we call `SetState(..., invalidateComponent: false)`

Now if you click the button, no Render message should be written to the console output: this proves that we're updating the native Label `without` recreating the component.

Of course, this is not possible every time (for example when a change in the state should result in a change of the component tree) but when it is, it should improve the responsiveness of the app.
