blazor webassembly 为什么我在页面和子组件之间无限循环?

blazor webassembly Why I am getting infinite looping between Page and subComponent?

我的应用程序在 VS2022 C# Blazor WASM 中使用 .Net 6 托管。我有一个带有子组件的 Blazor 页面,该页面具有允许 PAGE 查看 select-框的功能 Active/Inactive(两个选项)和一个用于客户名称列表(缩写)的 select 框。

PAGE 如下所示:

TOP 矩形是子组件,其“行为”类似于 returns(通过 CALLBACK)selected“CustomerID”(显示为 'ARCTB' ).子组件通过 CALLBACK 参数对带有 'selected' CustomerID 的父表单的“select-选择”(@onchange=) 作出反应,因此父页面可以为该 selected 客户。

在确定客户列表和第一个 CustomerID 的初始子组件 OnParametersSetAsync() 上,使用 CustomerID 的 List[0] 元素对 PAGE 进行回调。在 PAGE 的这一点上,对 PAGE 和子组件都进行了重新呈现。这会导致子组件的 OnParametersSetAsync() 再次触发,并再次触发 CALLBACK 以进行无限循环。

第二个矩形是 PAGE-html 的一部分,允许用户 select 活动或非活动车辆,将客户车辆列表过滤为 _listOfAllVehicles( v => v.IS_ACTIVE == true-or-false)

出现无限循环的问题是因为对PAGE的CALLBACK强制重新渲染,然后子组件从OnParametersSetAsync()方法执行另一个CALLBACK。这是我求解答的死循环问题

作为最新 Blazor 的新手,我不确定 ShouldRender() 是否可以用于 PAGE 或子组件或两者?也许使用子组件“标志”来表示“OkToCallback”以限制重复的 CALLBACK 调用。

欢迎您提出意见、问题和答案。

应@Marius的要求,子组件代码如下。我已经包含了停止无限循环的“_IsLoading”测试。

谢谢@Marius 的回答。 :-)

protected override async Task OnParametersSetAsync() {
    // Retain the Parameters.
    _LoggedInCustomerName = pLoggedInCustomerName;
    _LoggedInUserRoleName = pLoggedInRole;

    _IsUserNotFCI = (_LoggedInUserRoleName != "FCI");
    _IsActiveCustomers = (_ddlActive_Value == 1);

    await Task.Delay(10);
    _ddlCustomer_Value = RefreshCustomerList(_ddlActive_Value);

    if (_ddlCustomer_Value > 0) {

        // Set to first-option (index) (refer to wwwroot\index.html -- see OnAfterRender()
        if (_IsLoading) {
            // Update the selected customer.
            ChangeEventArgs evntArgs = new ChangeEventArgs();
            evntArgs.Value = _ddlCustomer_Value.ToString();
            await SelectedCustomerChanged(evntArgs);
            _IsLoading = false;
        }
    }

    base.OnParametersSet();
}

private int RefreshCustomerList(int pCustomersActiveFlag) {
    // Refresh the customer-list based on the 'ddlActiveFilter' ACTIVE-STATUS and USER-ROLE.
    // Return the zero-th element's UID_CUSTOMER of the list of customers.
    bool isActiveFlag = (pCustomersActiveFlag==1);
    int retValue = 0;
    if (_ListAllCustomers != null) {
        // When LOGGEDIN-USER is NOT FCI, reduce the list to ONLY the loggedin-user customer.
        if (_IsUserNotFCI) {
            // This returns a list of a single <Customer> record.
            _ListFilteredCustomers = _ListAllCustomers.Where(c => (c.TXT_CUSTOMER_NAME == _LoggedInCustomerName)).ToList();
        } else {
            // This returns a list of all ACTIVE or INACTIVE customers based on 'pCustomersActiveFlag' => 'isActiveFlag'.
            _ListFilteredCustomers = _ListAllCustomers.Where(c => (c.BOOL_IS_CUST_ACTIVE == isActiveFlag)).OrderBy(r => r.TXT_CUSTOMER_ABBREV).ToList();
        }

        // Set the 'ddlCustomer_Value' to the UID of the first-customer in the list.
        retValue = _ListFilteredCustomers[0].UID_CUSTOMER;
    }
    return retValue;
}   

private async Task SelectedCustomerChanged(ChangeEventArgs e) {  // This is the event after selection is made.
    int iArgValue = Convert.ToInt32(e.Value);
    _ddlCustomer_Value = Convert.ToInt32(e.Value);

    Customer customer = _ListFilteredCustomers!.Where(rec => rec.UID_CUSTOMER == _ddlCustomer_Value).FirstOrDefault();
    if (customer != null) {
        _SelectedCustUID = customer.UID_CUSTOMER;
        _SelectedCustName = customer.TXT_CUSTOMER_NAME;
    }


    // Callback to Parent.
    await OnCustomerSelection.InvokeAsync(_ddlCustomer_Value);

}   

OnParametersSetAsync and OnParametersSet 将在参数更改时触发,即使值与之前相同。您可以编写一些代码来避免这种情况。

示例:Is previous parameter value the same as current ? skip load : load

private string _cachedValue;

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

protected override async Task OnParametersSetAsync()
{
    if (parameterValue != _cachedValue)
    {
        _cachedValue = parameterValue;
        LoadComponent();
    }
}

private void LoadComponent() {
    //...
}

以上只是执行此操作的一种方法的示例。使用适合您的代码的逻辑。