microsoft / fluentui-blazor

Microsoft Fluent UI Blazor components library. For use with ASP.NET Core Blazor applications
https://www.fluentui-blazor.net
MIT License
3.3k stars 305 forks source link

fix: Rows render multiple times when DataGrid has changes (performance issue) #2057

Closed joriverm closed 2 weeks ago

joriverm commented 2 weeks ago

πŸ› Bug Report

Tbh, im not sure this is a bug or design fail on my side. However, i have an performance issue where we have a complex column template. we notice that when a cell content changes, all rows are rendered multiple times, which causes performance issues when there are a lot of rows. We were able to reproduce the basics of it, using basic controls/components in the Demo project. in the demo project it isn't really a problem, as the pc running it is fast enough to deal with the basic component, but if the component becomes a bit more complex it gets bad fast.

πŸ’» Repro or Code Sample

In the typical datagrid example i replaced the datagrid with the following changes. it has 1 column, containing a button to show more/other data

@using System.Collections.ObjectModel
@inject DataSource Data

<FluentDataGrid Items=@FilteredItems TGridItem="Country" GridTemplateColumns="80px 0.8fr 2fr 2fr 1fr 1fr 100px">
    <TemplateColumn TGridItem=Country Title="Test">
            <ChildContent>
                    <FluentButton OnClick=@(() => { OnButtonClick(context);})>clicky!</FluentButton>
                    @if(List.Contains(context))
                    {
                        <TestComponent/>
                    }
            </ChildContent>
        </TemplateColumn>
</FluentDataGrid>

the TestComponent has the following :

<FluentStack Orientation="Orientation.Horizontal">
    <span>@Id</span>
    <FluentButton OnClick="() => Id++">test</FluentButton>
</FluentStack>

@code {
    public int Id { get; set; } = 0;

    protected override Task OnParametersSetAsync()
    {
        Console.WriteLine("OnParametersSetAsync - TestComponent");
        return base.OnParametersSetAsync();
    }
}

i also added a Console.WriteLine in the datagrid in the OnPropertySet and RenderRow

πŸ€” Expected Behavior

The rows to be at most rendered once, to calculate all the rows state

😯 Current Behavior

The test component takes a while before its rendered, and the logs show it rendered the rows at least 3 times image

πŸ’ Possible Solution

i have no idea at this point why its doing this, otherwise i would have made a PR hehe

πŸ”¦ Context

This currently has an effect on my client's website as we have a column that should only show data when the button is pressed and a reason for showing the data is given. it takes multiple seconds to show the data because its rendering every row multiple times

🌍 Your Environment

vnbaaij commented 2 weeks ago

Hi,

This has to do with the way the FluentDataGrid is using ChildContent as a way of collecting the list of columns, the assumption is it's free to render that as often as it wants/needs. In order to discover when columns are added/removed/sorted, it has to be able to invoke ChildContent on each render. Same happens in this case with clicking on the button. There is no way to prevent the reloading of the data. For a solution, you should be looking for some way to perform the data retrieval conditionally.

See also #1514 for some more information. There is also a discussion topic on this: https://github.com/microsoft/fluentui-blazor/discussions/1982

Closing this one as it is not actionable from our side atm.

joriverm commented 2 weeks ago

Hey, thanks for the reply. makes sense thats why it happens. sadly our performance issues comes from it taking a few seconds just to re-render the components/rows, not just from getting data (which is a regular list for us, no api call).

ill see what i can do to hopefully move stuff around and render as less as possible when it isn't needed and move some stuff around.

thanks again :)