fluentui-blazor icon indicating copy to clipboard operation
fluentui-blazor copied to clipboard

fix: uncontrolled UI updates of values bound to FluentUI components when using blazorserver and callbacks with some workload

Open Brimerland opened this issue 3 years ago • 3 comments

🐛 Bug Report

Updating values which are two way bound to a FluentUI component during a "@onclick" callback in a Blazor server app will lead to uncontrolled repeated updates if the callback method did not return before a subsequent call.

This issue does not appear on client side Blazor (blazorwasm)!

💻 Repro or Code Sample

The Issue was found using @fluentui/[email protected] and Microsoft.Fast.Components.FluentUI 1.1.0.

Use your existing Blazor server app or create a new one following these steps:

  • dotnet new blazorserver -o BugFluentUIApp
  • cd BugFluentUIApp
  • dotnet add package Microsoft.Fast.Components.FluentUI
  • npm install --save @fluentui/web-components
  • move node_modules/@fluentui\web-components/dist/web-components.min.js to folder wwwroot/script
  • add <script type="module" src="script/web-components.min.js"></script> to Pages/_Layout.cshtml at the end of the head section
  • create new folder Components
  • create new file MyItem.razor inside Components folder
  • add content of the MyItem.razor component below
  • add <BugFluentUIApp.Components.MyItem/> to Pages/Index.razor
  • start application and press on the presented buttons

Contents of MyItem.razor

@using Microsoft.Fast.Components.FluentUI;

@if (FromInside)
{
    // "normal" use

    <button @onclick="UpdateAsync">Update Async</button>
    <button @onclick="UpdateBlocking">Update Blocking</button>
    <button @onclick="UpdateBlockingAsync">Update Blocking Async</button>
    <button @onclick="UpdateBlockingAsync_Workaround">Update Blocking Async Workaround</button>
    <br>
    @if (UseNumberField)
    {
        <FluentNumberField @bind-Value=BoundValue/>
        // you can also use a slider here
        //<FluentSlider @bind-Value=BoundValue/>
    }
    else
    {
        <input @bind-value=BoundValue />
    }

    @BoundValue    
}
else
{
    // setup to instance to show test

    <p>Press rapidly on the buttons. You will see uncontrolled updates using the 2nd and 3rd buttons in the version using the @nameof(FluentNumberField<int>) </p>
    <p>Binding the value to an input element (working):</p>
    <MyItem FromInside=true UseNumberField=false />
    <br />
    <p>Binding the value to an @nameof(FluentNumberField<int>) element (broken):</p>
    <MyItem FromInside=true UseNumberField=true />    
}


@code
{
    [Parameter]
    public bool FromInside { get; set; }

    [Parameter]
    public bool UseNumberField { get; set; }

    public int BoundValue;

    static int c;

    // ok
    public async Task UpdateAsync()
    {
        await Task.Delay(500);
        BoundValue = ++c;        
    }

    // broken
    public void UpdateBlocking()
    {
        // do some work which might block
        int i;        
        i = 100000000; 
        while (i-- > 0) ;

        BoundValue = ++c;
    }

    // still broken
    public async Task UpdateBlockingAsync()
    {
        await Task.Delay(10);
        
        // do some blocking work inside a task
        UpdateBlocking();
        
        await Task.Delay(10);
    }

    // ok
    public Task UpdateBlockingAsync_Workaround()
    {
        return Task.Run(UpdateBlocking);
    }
}

🤔 Expected Behavior

Values which are bound to FluentUI components should only update when changed by user or by component code.

😯 Current Behavior

https://user-images.githubusercontent.com/609797/154707861-a55c27d0-ac82-4fc2-a431-11cce1091c7a.mp4

If you press the buttons "Update Blocking" or "Update Blocking Async" in the second row rapidly the bound values keep updating forever. (Even after you have stopped pressing the buttons.)

For comparison a value is bound to a non FluentUI input in the first row. Pressing these buttons do not trigger the issue.

💁 Possible Solution

🔦 Context

If a user triggers this kind of issue the FluentUI components having bound values let the application run wild and not usable anymore. For example a slider or a number field which controls pagination.

🌍 Your Environment

  • OS & Device: Windows 10 (21H1) on PC
  • Browser Microsoft Edge, Google Chrome & Mozilla FireFox
  • .NET 6.0
  • Microsoft.Fast.Components.FluentUI 1.1.0
  • @fluentui/[email protected]

Brimerland avatar Feb 18 '22 15:02 Brimerland

I can reproduce the error. No idea yet what is causing this.

Is there any specific reason you are installing the web-components package? It is not needed for the Microsoft.Fast.Components.FluentUI package to do its thing...

vnbaaij avatar Feb 18 '22 15:02 vnbaaij

Is there any specific reason you are installing the web-components package?

I just installed the package because I needed the web-components version number for this bug report for better reproducibility.

Your "Getting Started" section mentions to use this script element <script type="module" src="https://cdn.jsdelivr.net/npm/@fluentui/web-components/dist/web-components.min.js"></script> to get the latest version. (Which i was using.) But I have no clue to find out which version this 'latest' version is. So, I installed the npm module to get the web-components.min.js and the matching version number.

Brimerland avatar Feb 18 '22 16:02 Brimerland

I just installed the package because I needed the web-components version number for this bug report for better reproducibility.

That's good! Hadn't thought about that.

vnbaaij avatar Feb 18 '22 22:02 vnbaaij

Thid is no longer happening in the latest version. Closing this

vnbaaij avatar Jan 05 '23 09:01 vnbaaij