使用 http post 并在 Blazor 中设置 class 时出现奇怪和意外的行为。为什么?
Weird and unexpected behaviour while using http post and set a class in Blazor. Why?
这是一个非常简单的登录屏幕...
@inject HttpClient Http
@inject User user
@page "/loginSignup"
<div class="text-center">
Logged: [@user.Name]
<EditForm class="form-signin" model="@loginForm" OnSubmit="@DoLogin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<InputText @bind-Value="loginForm.email" type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus />
<label for="inputPassword" class="sr-only">Password</label>
<InputText @bind-Value="loginForm.password" type="password" id="inputPassword" class="form-control" placeholder="Password" required />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">
<a @onclick='() => mode ="signup"' @onclick:preventDefault href="">Not registered ? Create an Account</a>
</p>
</EditForm>
</div>
@code {
private string mode = "login";
public LoginFormModel loginForm = new LoginFormModel();
private async void DoLogin()
{
var body = new LoginFormModel { email = loginForm.email, password = loginForm.password };
var response = await Http.PostAsJsonAsync("http://localhost:1337/customers/login", body);
User userSet = await response.Content.ReadFromJsonAsync<User>();
user.Name = "tst";
Console.WriteLine(user.Name);
}
public class LoginFormModel
{
public string email { get; set; }
public string password { get; set; }
}
}
当我提交时,html 上的 Logged: [@user.Name]
行不会显示任何内容,但控制台会显示 tst。如果我再次按下提交,它会按预期工作,这将在 Logged: [@user.Name]
和控制台上显示 TST。
我决定在 DoLogin 评论所有的行然后就离开了:
user.Name = "tst";
Console.WriteLine(user.Name);
以这种方式,这按预期工作。如果我按下提交,我可以在控制台和屏幕上看到 Tst。这意味着我的 http 调用以某种方式弄乱了渲染。为什么?
更多详情:
Core5,注入的用户是单例class。
问题是由您的异步方法的 return 类型引起的:您 return 一个 void
是非阻塞的。 The docs about this topic
非阻塞意味着调用者不会等待完成调用并立即继续下一个语句。 IE。在这种情况下,渲染引擎可能会在 DoLogin
仍然是 运行 且输出值尚未设置时触发组件更新。
要正确使用 await/async,您需要 return 方法中的等待任务。
旧答案(不再完全有效):
(我认为)问题是你更新了一个外部(注入的)对象。因此 Razor 组件实例将不会检测到任何内容在本地更新并且不会刷新。
我认为最好的解决方案是用局部变量替换名称
Logged: [UserName]
...
@code{
private string UserName {get;set;}
...
private async Task DoLogin()
{
...
UserName = "tst"; // or =user.Name;
}
}
另一种方法是使用 await InvokeAsync(StateHasChanged);
触发组件更新
这是一个非常简单的登录屏幕...
@inject HttpClient Http
@inject User user
@page "/loginSignup"
<div class="text-center">
Logged: [@user.Name]
<EditForm class="form-signin" model="@loginForm" OnSubmit="@DoLogin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<InputText @bind-Value="loginForm.email" type="email" id="inputEmail" class="form-control" placeholder="Email address" required autofocus />
<label for="inputPassword" class="sr-only">Password</label>
<InputText @bind-Value="loginForm.password" type="password" id="inputPassword" class="form-control" placeholder="Password" required />
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">
<a @onclick='() => mode ="signup"' @onclick:preventDefault href="">Not registered ? Create an Account</a>
</p>
</EditForm>
</div>
@code {
private string mode = "login";
public LoginFormModel loginForm = new LoginFormModel();
private async void DoLogin()
{
var body = new LoginFormModel { email = loginForm.email, password = loginForm.password };
var response = await Http.PostAsJsonAsync("http://localhost:1337/customers/login", body);
User userSet = await response.Content.ReadFromJsonAsync<User>();
user.Name = "tst";
Console.WriteLine(user.Name);
}
public class LoginFormModel
{
public string email { get; set; }
public string password { get; set; }
}
}
当我提交时,html 上的 Logged: [@user.Name]
行不会显示任何内容,但控制台会显示 tst。如果我再次按下提交,它会按预期工作,这将在 Logged: [@user.Name]
和控制台上显示 TST。
我决定在 DoLogin 评论所有的行然后就离开了:
user.Name = "tst";
Console.WriteLine(user.Name);
以这种方式,这按预期工作。如果我按下提交,我可以在控制台和屏幕上看到 Tst。这意味着我的 http 调用以某种方式弄乱了渲染。为什么?
更多详情:
Core5,注入的用户是单例class。
问题是由您的异步方法的 return 类型引起的:您 return 一个 void
是非阻塞的。 The docs about this topic
非阻塞意味着调用者不会等待完成调用并立即继续下一个语句。 IE。在这种情况下,渲染引擎可能会在 DoLogin
仍然是 运行 且输出值尚未设置时触发组件更新。
要正确使用 await/async,您需要 return 方法中的等待任务。
旧答案(不再完全有效):
(我认为)问题是你更新了一个外部(注入的)对象。因此 Razor 组件实例将不会检测到任何内容在本地更新并且不会刷新。
我认为最好的解决方案是用局部变量替换名称
Logged: [UserName]
...
@code{
private string UserName {get;set;}
...
private async Task DoLogin()
{
...
UserName = "tst"; // or =user.Name;
}
}
另一种方法是使用 await InvokeAsync(StateHasChanged);