adospace / reactorui-maui

MauiReactor is a MVU UI framework built on top of .NET MAUI
MIT License
555 stars 46 forks source link

Updating child component properties without invalidating layout #150

Closed destbg closed 10 months ago

destbg commented 10 months ago

Hello, like the title says, I want to update a property of a child component without having to rebuild the layout. For the built in components, that seems to be done with lambda functions, but I can't find a way to do the same with custom components.

Here is an example of what I want to achieve:

public class FirstState
{
    public string Text { get; set; } = "world!";
}

public class FirstComponent : Component<FirstState>
{
    public override VisualNode Render()
    {
        return new VerticalStackLayout
        {
            new SecondComponent()
                .Text(() => State.Text),

            new Button("Click me")
                .OnClicked(() => SetState(s => s.Text += "!", false)) // false, don't call Render, only lambdas
        };
    }
}

public class SecondComponent : Component
{
    private string text;

    public SecondComponent Text(Func<string> textFunc)
    {
        text = textFunc();
        // TODO: Also update when SetState with invalidateComponent = false is called from parent component
        return this;
    }

    public override VisualNode Render()
    {
        return new Label("Hello " + text);
    }
}

PS if it's okay to add a lambda function as a constructor of the Button class for updating the text, I'd appreciate it 🙏

adospace commented 10 months ago

Hi, I'm not sure what you're trying to achieve, but is not possible to render the child component without rendering the parent.

Setting invalidateComponent to false just means that you want to update the DependencyProperty of the native control without requiring a full render of the component.

Can you explain the reason behind the question? any specific use case?

destbg commented 10 months ago

I am exploring the library and seeing all that's it's capable of. Being able to update the UI without having to call the Render method again seems like a small optimization (since instead of recreating the whole UI, we only call the lambda functions on update). I wanted to know if it's possible to take advantage of that in custom components.

adospace commented 10 months ago

OK, no, that can't work because you're updating the state of the parent component and registering the callback function in the child. Anyway, I can say that MauiReactor has been written to take care of performance optimization from scratch. For example, native properties are updated only if their value are changed (seems obvious but not all MAUI controls are designed to compare the old vs. new value and skip the change, they often just transmit the new value down to the handler). Moreover, animations do not require a component render, they just update native properties values.

So, at least initially, I won't bother too much with the cost of rendering a component or using invalidateComponent everywhere.

destbg commented 10 months ago

Okay, thanks for taking the time to explain. Just one thing for "not all MAUI controls are designed to compare the old vs. new value", maybe they don't compare them since with the MVVM approach you have to call the PropertyChanged event handler to notify for change and you are advised to only call it whenever the value isn't the same as the previous (meaning we do that comparison in the model before notifying the view). For a library such as this, it's great to know those comparisons are handled by the library 👍

adospace commented 10 months ago

you're absolutely right!