前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Blazor-StateHasChanged

Blazor-StateHasChanged

作者头像
MaybeHC
发布2025-02-05 08:17:29
发布2025-02-05 08:17:29
6500
代码可运行
举报
文章被收录于专栏:技术之路技术之路
运行总次数:0
代码可运行

调用StateHasChanged()方法可以呈现组件UI,使用StateHasChanged方法也会增加成本开销。在Razor组件的呈现中,大部分的方法是不需要 通常情况下,Blazor会在状态变化时自动触发重新渲染,因此只有在需要显式控制重新渲染时(如异步操作或外部事件处理)才需要使用 StateHasChanged。 如果在 Blazor 的生命周期方法(如 OnInitializedAsyncOnParametersSetAsync)中,框架会自动检测并调用 StateHasChanged,因此在这些地方不需要手动调用。 自动呈现由ComponentBase 基类完成。

需要手动调用的时机 (1) 在异步处理程序中调用了多个异步方法。 (2) 在 Blazor 不受管理的外部调用事件处理程序。

下面我们通过例子来看看什么时候需要调用

异步调用

代码语言:javascript
代码运行次数:0
复制
@page "/injectPage"
@rendermode InteractiveAuto
<h3>InjectPage</h3>
<button @onclick="ShowName">修改</button>
<p>@name</p>
@code {
    string name = "0";
    public async Task ShowName(){
        name = "1";

        await Task.Delay(2000);
        name = "2";

        await Task.Delay(2000);
        name = "3";
    }
}

上面的代码如下,我们期望的结果应该是为点击时,显示数字为0,点击按钮后变为1,之后依次变化为2,3。我们运行代码来看看结果

我们发现调用后的结果和我们预测的不太一样,ui并没有显示中间过程,点击按钮后变化为1,之后直接变化为3了,没有变化为2的过程。

ComponentBase 只在第一次返回 Task,在 Task 已完成的情况下会触发重新呈现,若还有其它 await 等待,则必须手动调用 StateHasChanged()方法才能呈现。

在点击后变化为1,执行的是同步方法,之后等待结束后设置值为2,因为在中间过程不会重新呈现所以界面没有更新为2,等待Task全部结束后进行呈现,这是值已经被修改为3。我们这次调用下StateHasChanged()方法,来看看结果怎么样,代码修改如下:

代码语言:javascript
代码运行次数:0
复制
@page "/injectPage"
@rendermode InteractiveAuto
<h3>InjectPage</h3>
<button @onclick="ShowName">修改</button>
<p>@name</p>
@code {
    string name = "0";
    public async Task ShowName(){
        name = "1";

        await Task.Delay(2000);
        name = "2";
        StateHasChanged();

        await Task.Delay(2000);
        name = "3";
    }
}

这次我们在设置值2之后,调用了StateHasChanged来刷新UI,我们试试效果如何

这次我们发现是符合我们预期的结果了,我们在这种场景下可以去使用StateHasChanged方法来刷新UI。

外部调用

ComponentBase 只能管理自己生命周期内的方法(如 OnInitialized()或 OnParametersSetAsync())和 Blazor 触发的事件(如@onclick、@onchange 等)。 下面我们用一个例子看看,这个例子中我们创建一个Timer来调用值发生变化。代码如下

代码语言:javascript
代码运行次数:0
复制
@page "/injectPage"
@rendermode InteractiveAuto
@inject ILogger<InjectPage> logger;
<h3>InjectPage</h3>
<button>修改</button>
<p>@name</p>
@code {
    string name = "0";
    Timer timer;
    protected override void OnInitialized()
    {
        timer = new Timer(OnTimerCallback, null, 0, 4000);
        base.OnInitialized();
    }

    private void OnTimerCallback(object? state)
    {
        _ = InvokeAsync(() =>
        {
            logger.LogInformation("方法已经执行");
            name = "2";
        });
    }
}

看看执行的结果

我们看到执行结果,在定时器中的调用已经被执行但是页面UI没有被刷新。 我们修改之前的代码添加使用StateHasChanged方法来看看结果

代码语言:javascript
代码运行次数:0
复制
@page "/injectPage"
@rendermode InteractiveAuto
@inject ILogger<InjectPage> logger;
<h3>InjectPage</h3>
<button>修改</button>
<p>@name</p>
@code {
    string name = "0";
    Timer timer;
    protected override void OnInitialized()
    {
        timer = new Timer(OnTimerCallback, null, 0, 4000);
        base.OnInitialized();
    }

    private void OnTimerCallback(object? state)
    {
        _ = InvokeAsync(() =>
        {
            logger.LogInformation("方法已经执行");
            name = "2";
            StateHasChanged();
        });
    }
}

这次我们看到UI就可以刷新了。 timer 计时器上挂载的事件处理程序是 OnTimerCallback(),该事件处理程序是由计时器调用的,并不是由 ComponentBase 管理的,所以不会自动呈现 ,OnTimerCallback()事件中修改的的 UI 上呈现的数据,需要调用StateHasChanged()方法重新呈现。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-02-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 异步调用
  • 外部调用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档