如果方法包含等待调用,为什么我需要调用 StateHasChanged
Why do i need to call StateHasChanged if the method contains an await call
查看这段代码(blazor 服务器页面):
@page "/"
<div>@str</div>
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
@code
{
private string str { get; set; }
private void OnClick()
{
str = "Hello world";
}
}
此代码完美运行。当我点击按钮时,我可以在我的页面上看到“Hello world”。
现在看这段代码:
@page "/"
<div>@str</div>
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
@code
{
private string str { get; set; }
private async Task OnClick()
{
await ReadDataBase();
str = "Hello world";
StateHasChanged();
}
}
我不明白为什么,但如果我不放置 StateHasChanged(),str 不会立即刷新。我的问题是……为什么?
谢谢
原因是您没有 await
在 lambda 中使用异步方法。换句话说,将您的代码更改为:
<button @onclick="async eventArgs => { await OnClick(); }">Hello</button>
话虽如此,如果您所做的只是调用异步方法而从未实际使用等待的任务,则可以删除括号 { }
并将代码更改为以下内容:
<button @onclick="() => OnClick()">Hello</button>
如果您这样做,框架将为您将 lambda 包装在 Func<Task>
中。
现在,我假设您使用 lambda 是有原因的,例如您想向它传递一些参数。如果不是这种情况,您也可以像下面这样编写代码:
<button @onclick="OnClick">Hello</button>
当您不等待异步方法时,将继续执行而不等待您的任务完成。基本上,这是您的代码中发生的事情:
- 点击按钮
- 调用了 ReadDataBase
- StateHasChanged 由框架调用
str
还没有更新,所以UI不刷新
str
终于更新了
- 您需要手动调用
StateHasChanged
来更新 UI
您的版本缺少一个 return
,这将有效:
<button @onclick="eventArgs => { return OnClick(); }">Hello</button>
您可以缩短为:
<button @onclick="eventArgs => OnClick()">Hello</button>
当没有参数时,您可以将其简化为
<button @onclick="OnClick">Hello</button>
在所有三种情况下,分配给 @onclick
的方法现在 returns 一个任务,将等待。然后你就不再需要 StatehasChanged();
行了。
为 @onclick=
生成的代码适用于接受任务方法和(不)自动使用 eventArgs。
I do not understand why but the str is not refreshed immediately if i do not put StateHasChanged(). My question is ... why ?
这是部分正确的。 str 变量被分配了字符串“Hello world”,只有在对 ReadDataBase
的调用返回后页面才为 re-rendered。请注意,应等待对 OnClick
的调用,如下所示:
`@onclick="async eventArgs => { await OnClick(); }"`
但这不是“str 没有立即刷新”的原因。原因是在给 str
赋值之前调用了 ReadDataBase
方法...当您等待 ReadDataBase
方法时,调用代码将执行,并且框架执行其他任务...只有在 ReadDataBase
方法返回后(当任务完成时),OnClick
方法中的代码继续执行下一行,即字符串“Hello”的赋值world" 到 str
,然后组件才为 re-rendered,如果您添加对 StateHasChanged
方法的调用,或者更好地执行 @onclick="async eventArgs => { await OnClick(); }"
并删除对 [=23 的调用=]
结论:如果要给str
赋值并立即刷新显示,将str = "Hello world";
放在第一行,await ReadDataBase();
放在第二行。它无需调用 StateHasChanged
即可工作,即使您使用
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
而不是
@onclick="async eventArgs => { await OnClick(); }"
顺便说一句,我会做这样的事情:
<button @onclick="eventArgs => OnClick()">Hello</button>
现在尝试了解 "eventArgs => OnClick()"
和 "eventArgs => { OnClick(); }"
之间的区别
试试这个代码:
<div>@str</div>
<button @onclick="OnClick">Click me</button>
@code
{
private string str { get; set; }
private async Task OnClick()
{
str = "Hello world";
// Simulate an async call to ReadDataBase
await Task.Delay(3000);
}
}
更新和澄清:
我猜你知道什么时候不应该手动调用 StateHasChanged 方法,因此你的问题...确实,在过去,必须在组件状态发生变化后手动调用此方法,以便通知状态已更改的组件,它应该 re-render。后来,当涉及 UI 事件(例如 'click')时,手动调用 StateHasChanged 方法变得多余。其背后的原因是 UI 事件几乎总是导致组件状态的修改,因此让我们为开发人员节省手动添加它的负担。现在,由于您的 OnClick
方法是一个事件处理程序,因此不需要手动添加 StateHasChanged 方法,但如果不手动添加它,组件就不会刷新 (re-render)。出现该行为的原因是您同步调用 OnClick
,而没有返回应告知 Blazor OnClick
方法已完成的 Task 对象。在这种情况下,Blazor 无法知道 OnClick
方法何时完成,因此它不会自动调用 StateHasChanged 方法。但是,当您手动添加 StateHasChanged 方法时,组件会刷新 (re-rendered)。当然也可以不手动添加,而是异步调用OnClick
方法
查看这段代码(blazor 服务器页面):
@page "/"
<div>@str</div>
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
@code
{
private string str { get; set; }
private void OnClick()
{
str = "Hello world";
}
}
此代码完美运行。当我点击按钮时,我可以在我的页面上看到“Hello world”。
现在看这段代码:
@page "/"
<div>@str</div>
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
@code
{
private string str { get; set; }
private async Task OnClick()
{
await ReadDataBase();
str = "Hello world";
StateHasChanged();
}
}
我不明白为什么,但如果我不放置 StateHasChanged(),str 不会立即刷新。我的问题是……为什么?
谢谢
原因是您没有 await
在 lambda 中使用异步方法。换句话说,将您的代码更改为:
<button @onclick="async eventArgs => { await OnClick(); }">Hello</button>
话虽如此,如果您所做的只是调用异步方法而从未实际使用等待的任务,则可以删除括号 { }
并将代码更改为以下内容:
<button @onclick="() => OnClick()">Hello</button>
如果您这样做,框架将为您将 lambda 包装在 Func<Task>
中。
现在,我假设您使用 lambda 是有原因的,例如您想向它传递一些参数。如果不是这种情况,您也可以像下面这样编写代码:
<button @onclick="OnClick">Hello</button>
当您不等待异步方法时,将继续执行而不等待您的任务完成。基本上,这是您的代码中发生的事情:
- 点击按钮
- 调用了 ReadDataBase
- StateHasChanged 由框架调用
str
还没有更新,所以UI不刷新str
终于更新了- 您需要手动调用
StateHasChanged
来更新 UI
您的版本缺少一个 return
,这将有效:
<button @onclick="eventArgs => { return OnClick(); }">Hello</button>
您可以缩短为:
<button @onclick="eventArgs => OnClick()">Hello</button>
当没有参数时,您可以将其简化为
<button @onclick="OnClick">Hello</button>
在所有三种情况下,分配给 @onclick
的方法现在 returns 一个任务,将等待。然后你就不再需要 StatehasChanged();
行了。
为 @onclick=
生成的代码适用于接受任务方法和(不)自动使用 eventArgs。
I do not understand why but the str is not refreshed immediately if i do not put StateHasChanged(). My question is ... why ?
这是部分正确的。 str 变量被分配了字符串“Hello world”,只有在对 ReadDataBase
的调用返回后页面才为 re-rendered。请注意,应等待对 OnClick
的调用,如下所示:
`@onclick="async eventArgs => { await OnClick(); }"`
但这不是“str 没有立即刷新”的原因。原因是在给 str
赋值之前调用了 ReadDataBase
方法...当您等待 ReadDataBase
方法时,调用代码将执行,并且框架执行其他任务...只有在 ReadDataBase
方法返回后(当任务完成时),OnClick
方法中的代码继续执行下一行,即字符串“Hello”的赋值world" 到 str
,然后组件才为 re-rendered,如果您添加对 StateHasChanged
方法的调用,或者更好地执行 @onclick="async eventArgs => { await OnClick(); }"
并删除对 [=23 的调用=]
结论:如果要给str
赋值并立即刷新显示,将str = "Hello world";
放在第一行,await ReadDataBase();
放在第二行。它无需调用 StateHasChanged
即可工作,即使您使用
<button @onclick="eventArgs => { OnClick(); }">Hello</button>
而不是
@onclick="async eventArgs => { await OnClick(); }"
顺便说一句,我会做这样的事情:
<button @onclick="eventArgs => OnClick()">Hello</button>
现在尝试了解 "eventArgs => OnClick()"
和 "eventArgs => { OnClick(); }"
试试这个代码:
<div>@str</div>
<button @onclick="OnClick">Click me</button>
@code
{
private string str { get; set; }
private async Task OnClick()
{
str = "Hello world";
// Simulate an async call to ReadDataBase
await Task.Delay(3000);
}
}
更新和澄清:
我猜你知道什么时候不应该手动调用 StateHasChanged 方法,因此你的问题...确实,在过去,必须在组件状态发生变化后手动调用此方法,以便通知状态已更改的组件,它应该 re-render。后来,当涉及 UI 事件(例如 'click')时,手动调用 StateHasChanged 方法变得多余。其背后的原因是 UI 事件几乎总是导致组件状态的修改,因此让我们为开发人员节省手动添加它的负担。现在,由于您的 OnClick
方法是一个事件处理程序,因此不需要手动添加 StateHasChanged 方法,但如果不手动添加它,组件就不会刷新 (re-render)。出现该行为的原因是您同步调用 OnClick
,而没有返回应告知 Blazor OnClick
方法已完成的 Task 对象。在这种情况下,Blazor 无法知道 OnClick
方法何时完成,因此它不会自动调用 StateHasChanged 方法。但是,当您手动添加 StateHasChanged 方法时,组件会刷新 (re-rendered)。当然也可以不手动添加,而是异步调用OnClick
方法