fabulous-dev / Fabulous

Declarative UI framework for cross-platform mobile & desktop apps, using MVU and F# functional programming
https://fabulous.dev
Apache License 2.0
1.15k stars 122 forks source link

Rendering a new View.Grid displaces content inside #744

Closed rillstone closed 4 years ago

rillstone commented 4 years ago

When switching from one View.Grid to another, it seems to displace the content inside as it reuses the attributes such as the coldefs and rowdefs from the previous grid. I believe this could be a similar issue to #622 which was fixed in PR #627. However, I am experiencing similar behaviour to this issue now. I am using Fabulous 0.54.0 and Xamarin.Forms 4.6.0.726

Reproducing this issue with:

let view (model: Model) dispatch =
    match model.Page with
    | One ->
        View.ContentPage(
            content = View.Grid(
                coldefs = [Star; Stars 25.; Star],
                rowdefs = [Auto; Auto],
                children = [
                    yield View.Label(text = "Page One").Row(0).Column(1)
                    yield View.Button(text = "Change", command = (fun () -> dispatch RenderTwo)).Row(1).Column(1)
                ]
            )
        )
    | Two ->
        View.ContentPage(
            content = View.Grid(
                rowdefs = [Auto; Auto],
                children = [
                    yield View.Label(text = "Page Two").Row(0)
                    yield View.Button(text = "Change", command = (fun () -> dispatch RenderOne)).Row(1)
                ]
            )
        )

When clicking Change from Page One to Page Two, the content of the View.Grid in the second view shows as

I understand that the reason for this is when updating the views, the views are being reused from the canReuseView function I worked around this issue by adding a unique automationId to both grids, in order to get a false return in canReuseView for the canReuseAutomationId prevChild newChild condition:

| One ->
    View.ContentPage(
      content = View.Grid(
          automationId="PageOne",
          coldefs = [Star; Stars 25.; Star],
          rowdefs = [Auto; Auto],
          children = [
              yield View.Label(text = "Page One").Row(0).Column(1)
              yield View.Button(text = "Change", command = (fun () -> dispatch RenderTwo)).Row(1).Column(1)
          ]
      )
    )

I'm not quite satisfied with this workaround as the automationId should be used for automation testing. Is this expected behaviour from the view reuse logic? or could there be some missing checks/edge cases inside this canReuseView function causing views to be reused when they shouldn't be?

TIA

TimLariviere commented 4 years ago

@rillstone Thanks for the report! v0.54 seems ok. I don't reproduce with the sample you provided.

But I do reproduce in 0.55-preview. Will try to fix that.

In the meantime, please use v0.54 instead.

TimLariviere commented 4 years ago

Should be fixed in 0.55.0-preview3