【问题标题】:Blazor List<T> re-rendering missing when T element changed当 T 元素更改时,Blazor List<T> 重新渲染丢失
【发布时间】:2021-06-19 23:16:15
【问题描述】:

当我从表单组件更新对象时,我尝试更新对象列表。但是如果我的对象更新得很好,我的列表不是。

这里是我的父组件

@inject ApiClient Api

@if (normes != null)
{
    <ul>
        @foreach (var item in normes)
        {
            <li @onclick="@(()=> norme = item)">@item.Name</li>
        }
    </ul>
}

@if (norme != null)
{
    <label>The bind parameter in the parent: @norme.Name</label>
    <Edit @bind-Norme="norme" />
}

@code {

    private List<Norme> normes { get; set; }

    private Norme norme { get; set; }

    protected override async Task OnInitializedAsync()
    {
        normes = await Api.GetAsync<List<Norme>>("norme");
    }
}

我从一个 api 获得一个列表,当我选择一个 Norme à 显示一个表单组件来编辑它。

这里是我的子组件:

@inject ApiClient Api

<Loader WaitFor="localNorme">
    <EditForm Model="localNorme" OnValidSubmit="OnValidSubmit">
        <DataAnnotationsValidator />
        
        @if (localNorme.Id == 0)
        {
            <h3>Nouvelle norme</h3>
        }
        else
        {
            <h3>Norme n° @localNorme.Id</h3>
        }

        <div class="btn-toolbar justify-content-end" role="toolbar">
            <div class="btn-group mr-2" role="group">
                <button type="submit" class="btn btn-outline-success"><i class="bi-save" /></button>
                <button type="button" class="btn btn-outline-danger" @onclick="OnCancelClick"><i class="bi-x" /></button>
            </div>
        </div>


        <div class="overflow-auto">

            <div class="form-group">
                <FormLabel For="@(()=>localNorme.Name)" />
                <InputText @bind-Value="localNorme.Name" class="form-control" />
                <ValidationMessage For="@(()=>localNorme.Name)" />
            </div>

            <input type="hidden" @bind-value="localNorme.Id" />
        </div>
    </EditForm>

    <label>The bind parameter in the child: @Norme.Name</label>
</Loader>


@code {
    [Parameter] public Norme Norme { get; set; }

    [Parameter] public EventCallback<Norme> NormeChanged { get; set; }

    private Norme localNorme;

    protected override async Task OnParametersSetAsync()
    {
        await LoadAsync();
    }

    private async Task LoadAsync()
    {
        if (Norme.Id > 0)
        {
            localNorme = await Api.GetAsync<Norme>($"norme/{Norme.Id}");
        }
        else
        {
            localNorme = new Norme();
        }
    }

    private async Task OnValidSubmit(EditContext context)
    {
        Norme model = context.Model as Norme;
        if (model.Id > 0)
        {
            // Update
            model = await Api.PutAsync<Norme>($"norme/{Norme.Id}", model);
        }
        else
        {
            // Create
            model = await Api.PostAsync<Norme>("norme", model);
        }
        await NormeChanged.InvokeAsync(model); // bound object update
    }

    private async Task OnCancelClick()
    {
        await LoadAsync();
    }
}

这是我提交表单后的结果:

如你所见,我的列表没有更新。

首先,在我的子组件中,我使用我的 Norme 参数作为表单中的模型。但是我的父参数和 List 在我输入的 OnChanged 事件中进行了更新。 所以我在我的表单中插入一个 localNorme 作为模型,当它提交时,我使用 EventCallback 来更新绑定参数。 在我的父母中,我的参数得到了很好的更新,但我不知道我错过了什么来触发我的列表更新。

我尝试插入一些 StateHasChanged() 但没有任何改变。如果我更新父级中的规范属性,我还会检查我的列表是否更新。

谢谢。

【问题讨论】:

    标签: c# blazor


    【解决方案1】:

    我认为您要更新的列表是“规范”。

    您在此处设置了该列表:

    protected override async Task OnInitializedAsync()
    {
        normes = await Api.GetAsync<List<Norme>>("norme");
    }
    

    仅在父级首次添加到渲染树时调用。

    您需要一种在项目发生更改时更新它的方法。

    简单的方法是手动绑定 Edit 组件,这样您就可以为 NormeChanged 回调注册一个处理程序

    <Edit Norme="norme" NormeChanged=RefreshList/>
    

    然后 RefreshList 可以更新列表“规范”并刷新父组件

    async Task RefreshList(Norme norme) 
    {
      normes = await Api.GetAsync<List<Norme>>("norme");
      StateHasChanged();
    }
    

    当然有很多方法可以做到这一点 - 集中状态、事件聚合器、消息总线 - 这是最简单的展示方式。

    【讨论】:

    • 我想过这个解决方案,你甚至不必把StateHasChanged()。它有效,但我觉得我对 api 做了不必要的调用。我想这很好,但我会采取任何更优雅的解决方案;)谢谢(我会等几天才能接受这个答案)
    • 哦,我明白了 - 很难按照这里的代码进行操作 - 我想我现在明白了 - 尝试在您呈现的列表项中添加 @key &lt;li @key=item @onclick="@(()=&gt; norme = item)"&gt;@item.Name&lt;/li&gt; - 它可能正在更新集合,但不会更改 UI,因为它检测更改的方式
    • @key 指令在这种情况下没有影响。但是我在回调中使用真实数据(大约 10k 个条目)尝试了 api 调用,响应时间几乎是即时的(我的列表显示在分页表中),所以我会采用这个解决方案。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多