2023-11-10

Understanding QuickGrid internals: "Defer hack"

I am studying the source code of the QuickGrid from Blazor (ASP.NET Core 8). The implementation leverages some internal knowledge on how Blazor handles the actual rendering in order to collect all ColumnBase child components. It does so by initiating and ending a "collecting session" and during this session all ColumnBase child components attach themselves to the cascaded grid context.

<CascadingValue TValue="InternalGridContext<TGridItem>" IsFixed="true" Value="@_internalGridContext">
    @{ StartCollectingColumns(); }
    @ChildContent
    <Defer>
        @{ FinishCollectingColumns(); }
        <ColumnsCollectedNotifier TGridItem="TGridItem" />

        @* HTML table... *@
    </Defer>
</CascadingValue>

The ColumnBase components inside the ChildContent execute the following code in their BuildRenderTree method:

InternalGridContext.Grid.AddColumn(this, InitialSortDirection, IsDefaultSortColumn);

The Defer component ist built like this:

// This is used by QuickGrid to move its body rendering to the end of the render queue so we can collect
// the list of child columns first. It has to be public only because it's used from .razor logic.
public sealed class Defer : ComponentBase
{
    [Parameter] public RenderFragment? ChildContent { get; set; }

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        builder.AddContent(0, ChildContent);
    }
}

There is also a comment in the Defer component explaining what it does which I do understand. However, I do not exactly understand how and why this works. Can someone explain to me the details on how and why this works?

It somehow suggests that RenderFragments are delayed when rendering. But thats not really intuitive to me. I am thinking of the rendering as some sort of a left-order tree traversal of the nodes including the RenderFragments. But it almost looks like RenderFragments are not traversed initially.



No comments:

Post a Comment