参数/CascadingParameter 不更新对象

我想通过 TodoItem 更新子组件 TodoComponent 中的 EventCallback

在我的 TodoPage.razor.cs 中,我实现了一个更新方法:

public async void UpdateTodo(TodoItem todoItem)
{
    await Http.PutAsJsonAsync("todo", todoItem);
    await RefreshTodos();
}

然后我试图传递给负责渲染对象的 TodoComponent

@foreach (var item in @TodoItems)
{
    <div class="row">
            <CascadingValue Value=@item Name="TodoItem">
                <TodoComponent UpdateCallback="@(async () => UpdateTodo(item))">
                </TodoComponent>
            </CascadingValue>
    </div>
}

TodoComponent.razor

@inherits ListOfTodos.Client.Components.TodoComponentBase
<div class="input-group col-12">
    <div class="input-group-prepend">
        <div class="input-group-text">
            <input type="checkbox" @bind="@TodoItem.IsDone" onclick="@UpdateCallback">
        </div>
    </div>

    <div class="col-8">
        <input type="text" class="form-control" @bind="@TodoItem.TaskName" oninput="@UpdateCallback" />
    </div>

    <div class="input-group-append">
        <input type="date" @bind="@TodoItem.DueDate" />
    </div>
</div>

附加信息:

public async Task RefreshTodos()
{
    TodoItems = await Http.GetFromJsonAsync<List<TodoItem>>("todo");
    StateHasChanged();
}
public class TodoComponentBase : ComponentBase
{
    [CascadingParameter(Name = "TodoItem")]
    public TodoItem TodoItem { get; set; }

    [Parameter]
    public EventCallback<TodoItem> UpdateCallback { get; set; }

    protected override Task OnInitializedAsync()
    {
        return base.OnInitializedAsync();
    }

}

当我调用 UpdateCallback 虽然 onchangeoninputTodoItem 就像它根本没有更新一样,我不知道绑定是否按我的意愿工作去做。

如何正确地将对象传递给子组件并正确更新?

这是 github 存储库: https://github.com/DgoNeves/Blazor.ListOfTodos 它在内存中工作,因此您不需要任何数据库来运行它。

编辑:我不完全知道为什么会发生这种情况,但显然控制器调用是出于某种原因。 Blazor Update Behind

stack overflow Parameter / CascadingParameter not updating object
原文答案
author avatar

接受的答案

我想通了!

@bind="@TodoItem.TaskName" 默认执行 onChange

onInput 显然发生在 onChange 之前所以在屏幕截图中当我在它后面得到 1 个字符时意味着它没有更新 TodoItem.TaskName 因为这是下一步。

如果我真的想在每次击键时调用 API,我需要将其更改为:

@bind-value="@TodoItem.TaskName" @bind-value:event="oninput" onchange="@UpdateCallback"

通过这种方式,我将绑定更改为 onInput 并调用 UpdateCallback onChange 。因为 onInput happens first 我在 onChange 上获得了更新值,因此传递了正确的值。

来自我发现这个的来源: https://github.com/dotnet/aspnetcore/issues/15554 他和我有完全相同的错误


答案:

作者头像

StateHasChanged(); 仅使用 Childs 更新当前页面,不影响父组件。

对于父子组件之间的通信,必须使用 EventCallback

<CascadingValue Value="yourModel">
    <ChildComponent OnStateHasChanged="OnStateHasChanged" />
</CascadingValue>

父组件

private void OnStateHasChanged()
{
    StateHasChanged();
}

子组件

[Parameter]
public EventCallback OnStateHasChanged { get; set; }

private async Task OnUpdatedChild()
{
      await OnStateHasChanged.InvokeAsync();
}
作者头像

好的,我刚知道你的问题。这是你的 UpdateTodo 方法:
异步方法必须返回 Task 或 ValueTask。更新您的代码:

public async Task UpdateTodo(TodoItem todoItem)
{
    await Http.PutAsJsonAsync("todo", todoItem);
    await RefreshTodos();
}