dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
35.36k stars 9.99k forks source link

Blazor: Inconsistent component lifetimes inside an EditForm #17753

Closed mrpmorris closed 4 years ago

mrpmorris commented 4 years ago

Describe the bug

Components within an EditForm are destroyed/recreated whenever the Model changes, but this does not happen in my own custom component.

To Reproduce

Alter Index.razor

@page "/"

<EditForm Model=@TheModel>
    <InputText2/>
</EditForm>
<NotAnEditForm Model=@TheModel>
    <InputText2/>
</NotAnEditForm>
<button type="button" @onclick=CreateNewModel>Create new</button>

@code {
  MyModel TheModel = new MyModel();

  void CreateNewModel()
  {
      TheModel = new MyModel { FirstName = "X" };
  }

  public class MyModel
  {
      public string FirstName { get; set; }
  }
}

In /Shared create NotAnEditForm.razor

<CascadingValue Value=EditContext IsFixed=true>
    @ChildContent
</CascadingValue>
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public object Model
    {
        get => EditContext.Model;
        set
        {
            EditContext = new EditContext(value);
        }
    }

    EditContext EditContext { get; set; }
}

In /Shared create InputText2.cs

public class InputText2 : ComponentBase
{
    public DateTime CreatedOn = DateTime.UtcNow;

    [CascadingParameter]
    public EditContext CascadedEditContext { get; set; }

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        builder.AddMarkupContent(0, CreatedOn.ToString("HH:mm:ss"));
    }
}

Run the app and click the "Create new" button. The date of the InputText2 component within the EditForm is updated, therefore it is being recreated, but the InputText2 component within the NotAnEditForm remains unaltered.

javiercn commented 4 years ago

@mrpmorris thanks for contacting us.

I believe this is due to the IsFixed=true you have in your cascading value. That will make it available but will not trigger any updates to it. In the EditForm case the value gets updated and triggers a parameter update.

@SteveSandersonMS Is this correct?

mrpmorris commented 4 years ago

The EditForm also uses IsFixed=true.

However, it seems that the EditForm recreates all of its child content by using OpenRegion(EditContext.GetHashCode) - so when the EditContext changes the region's sequence ID changes - resulting in controls being destroyed and recreated.

I'll close this issue.

Thanks