Blazor 中的 StateHasChanged 目标

Posted

技术标签:

【中文标题】Blazor 中的 StateHasChanged 目标【英文标题】:StateHasChanged goal in Blazor 【发布时间】:2020-08-11 02:25:54 【问题描述】:

看看这个非常基本的组件:

<div>
    @param1
    <button @onclick="@btn_on_click">Cliquez là</button>
</div>

@code

    [Parameter]
    public int param1  get; set; 

    [Parameter]
    public Action<int> on_evt_test_fire  get; set; 

    void btn_on_click()
    
        param1 += 1;
        this.on_evt_test_fire(param1);
    

看看这个非常基本的页面:

@message

<button @onclick="@on_btn_click">Click me</button>

<MyComponent param1="1"  on_evt_test_fire="@on_evt" />
<MyComponent param1="2" on_evt_test_fire="@on_evt" />

@code 

    private String message = "";

    private void on_evt(int param_evt)
    
        message = "Button clicked inside component";

        StateHasChanged();
    

    private async Task on_btn_click()
    
        message = "Button clicked in this page";
    

我对 StateHasChanged() 有疑问。

我的第一个问题是:为什么我应该在 on_evt 中调用 StateHasChanged 而在 on_btn_click 中却没有必要。这两种方法之间的唯一区别是第一种是从组件内部调用的。在这种特定情况下,我为什么要调用 StateHasChanged ?

当我调用 StateHasChanged() 时,这 2 个组件被重置:它们取初始值...

感谢您的帮助

【问题讨论】:

【参考方案1】:

而在 on_btn_click 中则不需要

on_btn_click 不需要,因为 UI 事件会自动调用 StateHasChanged 方法。

[Parameter]
  public Action<int> on_evt_test_fire  get; set; 

您不应该使用 Action 委托。请改用 EventCallback 'delegate',如下所示:

注意:当你使用Action委托时,事件的目标是当前组件(子组件),而当你使用EventCallback时,目标是父组件,这就是为什么你不需要添加调用到 StateHasChanged 方法。在发现 EventCallback 之前,我们必须调用 StateHasChanged 方法。很久以前的事了……

[Parameter]
public EventCallback<int> on_evt_test_fire  get; set; 

你应该这样称呼它:

public async Task btn_on_click()

   if( on_evt_test_fire.HasDelegate)
   
       temp++;
       await on_evt_test_fire.InvokeAsync(temp);
    
 

您不应使用 param1 参数来增加其值。定义 一个新变量,并为其分配了 param1 中的值 OnInitialized 方法如 这个:

  protected override void OnInitialized()
  
      temp = param1;
  

当我调用 StateHasChanged() 时,这两个组件被重置:它们取初始值..

--

不要创建写入自己的参数属性的组件 在以下情况下会覆盖参数:

子组件的内容使用 RenderFragment 呈现。

StateHasChanged 在父组件中被调用。 参数被重置,因为在调用 StateHasChanged 并且向子组件提供新参数值时父组件会重新呈现。

Source here:

See more here:

【讨论】:

我不同意:在 UI 事件上不会自动调用 StateHasChanged。这不是 StateHasChanged,因为我没有得到相同的结果/行为 “我不同意:在 UI 事件上不会自动调用 StateHasChanged”当然可以。您能否向我展示一个不调用 StateHasChanged 就无法工作的 UI 事件处理程序。 “这不是 StateHasChanged,因为我没有得到相同的结果/行为”不确定您的意思? 我偶然发现了这个讨论,因为实际上我面临着类似的情况。所以我发现,如果回调没有在组件上设置值,那么它并没有重新渲染我的组件。因此,我正在检查 EventCallback 的 HasDelegate 属性,如果它为假,我将自己调用 StateHasChanged。这通常对我有所帮助,但我不确定这是否是解决此问题的最佳方法。【参考方案2】:

我相信@onClick 回调会由于某些隐藏的逻辑而强制子重新渲染。当分配给按钮的 @onClick 时,您的回调或事件很可能被添加到 onClick 在内部执行的操作列表中。对此持保留态度,这只是我的理论。

编辑:您的参数被重置是因为 setState() 迫使您的父母使用硬编码的“1”和“2”从头开始重新渲染。当 onbuttonclicked 事件触发时,我相信它会在组件内部设置状态,从而保留数据。多加点盐。

【讨论】:

有没有办法在不重新初始化我的 2 个组件实例的情况下刷新“消息”变量显示? 尝试在“myComponent”中设置状态,这将重新渲染组件而不会丢失数据。如果你将状态设置为父级,你将丢失数据。【参考方案3】:

@Henk 和@SilenceAmongCrows 的答案都是正确的。要添加的另一件事是,在您的子组件中,如果您使用 EventCallBack&lt;T&gt; 而不是 Action&lt;T&gt; 并将子组件中的 param1 属性绑定到父组件的 @code 块中的属性,则 Blazor引擎会更好地跟踪刷新什么以及何时刷新。

【讨论】:

以上是关于Blazor 中的 StateHasChanged 目标的主要内容,如果未能解决你的问题,请参考以下文章

何时在 Blazor 组件中调用 StateHasChanged()

Blazor 组件在 StateHasChanged() 之后未更新

我应该何时调用 StateHasChanged 以及 Blazor 何时自动拦截某些更改?

Blazor StateHasChanged 无法正常工作

使用 StateHasChanged 从父组件刷新 Blazor 服务器子组件

Blazor 重新渲染组件块元素 [关闭]