为什么 Blazor 会将组件渲染两次?

7

我有一个简单的Blazor组件。

<div @onclick="HandleClick">Click me</div>

@code {

    public async Task HandleClick()
    {
        await Task.Run(()=> System.Threading.Thread.Sleep(1000));
    }

    protected override void OnAfterRender(bool firstRender)
    {
        Console.WriteLine("Rendered");
    }
}

当我点击名称为“Rendered”的
时,控制台会打印出“Rendered”,并在1秒后再次打印,这意味着Blazor已经将组件渲染了两次。我知道Blazor在将事件分派给组件的过程中会触发组件的自动重新渲染。
但是为什么任务完成后它会重新渲染?如何避免第二次渲染?
我在OnAfterRender生命周期挂钩中有一些JS互操作,现在它运行了两次。我可以添加某种计数器,但那样会污染我的代码,我想避免这种情况。如果我的HandleClick只是一个简单的公共void方法,那就没问题了,但这并不总是可能的。

当您将HandleClick设置为非异步时,它将运行。您看到的是在等待之前和之后进行渲染。 - H H
但为什么任务等待后才呈现? - partyelite
1
UI 在 await Task.Run 之前和之后都被刷新,可以参考:https://dev59.com/1FMI5IYBdhLWcg3wRZXJ - dani herrera
2个回答

6
您可以像这样使用 firstRender 变量:
if(firstRender)
{
   // Call JSInterop to initialize your js functions, etc.
   // This code will execute only once in the component life cycle.
   // The variable firstRender is true only after the first rendering of the 
   // component; that is, after the component has been created and initialized.
   // Now, when you click the div element firstRender is false, but still the 
   // component is rendered twice, before the awaited method (Task.Run) is called,
   // and after the awaited method completes. The first render occurs because UI 
   // event automatically invoke the StateHasChanged method. The second render 
   // occurs also automatically after an awaited method in an async method 
   // completes. This is how Blazor works, and it shouldn't bother you. 
} 

3

我曾经面临同样的问题,但我的解决方案与@enet提到的不同。

如果您通过循环(例如foreach循环)显示组件,则需要将@key属性设置到组件上。在我的情况下,我有相同的组件,它接收了不同唯一键的相同类型对象,但是Blazor无法区分两者之间的差异。因此,当其中一个数据发生更改时,Blazor会生成所有这些组件。

当您传递@key="Your-unique-key"时,Blazor会监视该键而不是整个模型实例。

值得阅读Microsoft关于此事的说明:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接