数据驱动组件的 Blazor 渲染优化

问题描述 投票:0回答:2

我对如何优化典型数据驱动的 Blazor 组件的渲染感到困惑。考虑以下简化组件(部分):

public partial class FooComponent: ComponentBase
{
    [Inject]
    protected IBarService BarService { get; set; }

    [Parameter]
    public string OptionalParameter1 { get; set; }

    [Parameter] 
    public string OptionalParameter2 { get; set; };

    protected IEnumerable<BarItem> Items { get; set; }

    protected override Task OnParametersSetAsync()
    {
        this.Items = await this.BarService.GetItemsAsync(this.OptionalParameter1, this.OptionalParameter2);
    }
}

该组件有两个可选参数。它们通常可以是服务调用的一些过滤值。组件无法知道父组件是否会设置这些参数(因为它们是可选的)。每当设置参数时,组件都会通过(昂贵的)异步服务调用检索

BarItem
项目列表。然后组件标记以某种方式呈现
Items
列表。

问题是每次设置参数时都会调用

OnParametersSetAsync
,导致组件重新渲染并进行另一个服务调用。我可以通过检查参数值是否更改来部分优化它,但仍然会有多个服务调用。

  • 如果两个参数都没有设置,服务调用只会发生一次(很好)。
  • 如果设置了一个参数,服务调用会发生两次(第一次使用错误的参数值)。
  • 如果两个参数都设置,则服务调用会发生 3 次(前 2 次参数值错误)。

在具有更多属性的现实组件中,这可能很快会导致许多不需要的服务调用。如果对所有参数调用一次

OnParametersSetAsync
,这不会是问题(我知道 Blazor 不会以这种方式工作)。

我可以做些什么来确保服务调用仅使用正确的参数值发生一次吗?在我看来,这似乎是数据驱动组件中非常常见的场景,如果无法(有效)实现,这将是 Blazor 的真正缺点。

asp.net-core blazor blazor-server-side
2个回答
0
投票

昨天在 dotnet Conf Focus Blazor 上,Daniel Roth 展示了类似的东西。 要解决此问题,您可以使用每次设置其中一个参数时启动的计时器。如果计时器达到时间限制,您将调用搜索请求。 这称为去抖。

该部分的 YouTube 链接

如果可以的话,我会尝试挖掘 github 存储库来进行演示。


0
投票

我也遇到过这个问题,我也同意这是相当乏味的。在这里,我根据我的痛苦经历,以列表的形式提出一些反馈。希望这个对你有帮助;如果没有,请忽略它。

  1. 避免在参数中使用引用类型。如果我没记错的话(希望如此),引用类型总是会触发 OnParametersSet,而值类型仅在发生更改时才会触发。

  2. 使用可空类型,如 string?、bool?、int?这样您就可以检查是否设置了参数。

  3. 在检查参数是否已更改时,我总是使用前缀“Param”声明 [Parameter] 以及我在其下面的组件中实际使用的属性,因此我永远不会被迷惑。示例如下:

     @code {
    
     [Parameter] public string? PARAMOptionalParameter1 { get; set; }
     private string? OptionalParameter1 { get; set; }
    
     [Parameter] public string? PARAMOptionalParameter2 { get; set; }
     private string? OptionalParameter2 { get; set; }
    
     private bool _shouldRender;
     private bool _shouldDownloadData;
    
     private void FunctionToCheckForParamtersChange()
     {
         _shouldRender = false;
         _shouldDownloadData = false;
    
         if (PARAMOptionalParameter1 == OptionalParameter1)
         {
             // Do nothing or whatever you like
         }
         else
         {
             OptionalParameter1 = PARAMOptionalParameter1; 
             _shouldRender = true;
             _shouldDownloadData = true;
         }
         //Other stuff and parameters, you get the idea
     }
    
     protected override bool ShouldRender()
     {
         return _shouldRender;
     }
    
     protected override async Task OnParametersSetAsync()
     {
         FunctionToCheckForParamtersChange();
         if (_shouldDownloadData)
         {
             // DATA download
         }
     }
    }
    
  4. 最简洁的方法是将所有参数分组到名为 YourComponentConfig 的类/结构中。为此类或结构实现自定义比较器,并包含一个布尔标志来指示是否设置了所有参数。因此,您可以将 FunctionToCheckForParametersChange 方法简化为一行:if (ParamConfig == Config)。

  5. 或者,您可以使用一种不太传统的方法,即创建对组件的引用并直接从父控制器修改其参数(尽管选项 5 更好)。例如:

    @代码 { 成分? ComponentRef{获取;设置;}

    无效SetData(){ ComponentRef?.SetMyData("Data1","Data2"); // 请记住,我们的自定义 SetMyData 方法超出了渲染循环,因此您应该放入 SetMyData InvokeAsync(StateHasChanged) 以使渲染发生。 } }

© www.soinside.com 2019 - 2024. All rights reserved.