WebAssembly Performance Improvement in Syncfusion Blazor DataGrid | Syncfusion Blogs
Detailed Blog page Skeleton loader
WASM Performance Improvement in Syncfusion Blazor Data Grid

The Syncfusion Blazor DataGrid is a feature-rich component for displaying data in a tabular format. Its wide range of functionalities includes data binding, editing, filtering, custom sorting, aggregating rows, selection, and support to export to Excel, CSV, and PDF formats.

In this blog, we are going to discuss the improvements made in the Blazor DataGrid’s performance in WASM (WebAssembly) applications for the 2020 Volume 3 release compared to the previous release version (18.2.0.44). The comparison is fully based on the performance best practice guidelines suggested in the Blazor WebAssembly application.

We received various requests from our customers about improving the DataGrid’s performance in Blazor WASM applications. So, in response, we’ve taken immediate action and improved the performance for the following features in Blazor WebAssembly:

  • Selection
  • Column resizing
  • Filtering
  • Column chooser
  • Column menu
  • Column menu—submenu
  • Context menu

Even though we improved the Blazor DataGrid’s performance at the source level, the following Blazor WASM behaviors needed to be avoided on the application side while using our Blazor DataGrid events to improve performance further:

Avoid unnecessary component rendering

Each cell in the grid component and its child component will be checked for re-rendering by the Blazor diffing algorithm. For instance, the EventCallBack method in the application or grid will check every child component once the event callback is completed.

The newly provided PreventRender method helps you avoid unnecessary re-rendering of the grid component. This method internally overrides the ShouldRender method of the grid to prevent rendering.

In the following example:

  • The PreventRender method is called in the IncrementCount method, which is a click callback.
  • The grid component will not be a part of the rendering, which happens as a result of the click event, and the currentCount alone will be updated.
<h1>Counter</h1>

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

<SfGrid @ref="grid" DataSource="@Orders" AllowPaging="true">
    <GridColumns>
        <GridColumn Type="ColumnType.CheckBox" Width="50"></GridColumn>
        <GridColumn Field=@nameof(Order.OrderID) HeaderText="Order ID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
        <GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
        <GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
        <GridColumn Field="@nameof(Order.Verified)" DisplayAsCheckBox="true" Width="70"></GridColumn>
    </GridColumns>
</SfGrid>


@code {
    SfGrid<Order> grid { get; set; }
    private int currentCount = 0;
    public List<Order> Orders { get; set; }

    protected override void OnInitialized()
    {
        Orders = Enumerable.Range(1, 75).Select(x => new Order()
        {
            OrderID = 1000 + x,
            CustomerID = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)],
            Freight = 2.1 * x,
            OrderDate = DateTime.Now.AddDays(-x),
            Verified = (new bool[] { true, false })[new Random().Next(2)]
        }).ToList();
    }

    private void IncrementCount()
    {
        grid.PreventRender();
        currentCount++;
    }

    public class Order
    {
        public int? OrderID { get; set; }
        public string CustomerID { get; set; }
        public DateTime? OrderDate { get; set; }
        public double? Freight { get; set; }
        public bool Verified { get; set; }
    }

}

Note:

  • The PreventRender method accepts only Boolean arguments that accept true or false values to disable or enable rendering, respectively.
  • The PreventRender method can be used only after the grid component has completed its initial rendering. Calling this method during initial rendering will not have any effect.

Avoid unnecessary component rendering after grid events

When a callback method is assigned to the grid event, the StateHasChanged method will be called in the parent component of the grid after the completion of the event. This would thereby initiate re-rendering.

You can prevent this re-rendering of the grid component by setting the PreventRender property of the corresponding event argument to true.

In the following example:

  • RowSelected event is bound to a callback method. Once the row selection event is completed, the StateHasChanged method will be invoked for the parent component.
  • RowSelectEventArgs<Order>.PreventRender is set to true. Now, the grid will not be a part of the StateHasChanged method that is invoked as result of the grid action.
<p>Selected OrderID: <span style="color:red">@SelectedOrder.OrderID</span></p>

<SfGrid @ref="grid" DataSource="@Orders">
    <GridSelectionSettings PersistSelection="true"></GridSelectionSettings>
    <GridColumns>
        <GridColumn Type="ColumnType.CheckBox" Width="50"></GridColumn>
        <GridColumn Field=@nameof(Order.OrderID) IsPrimaryKey="true" HeaderText="Order ID" TextAlign="TextAlign.Right" Width="120"></GridColumn>
        <GridColumn Field=@nameof(Order.CustomerID) HeaderText="Customer Name" Width="150"></GridColumn>
        <GridColumn Field=@nameof(Order.OrderDate) HeaderText=" Order Date" Format="d" Type="ColumnType.Date" TextAlign="TextAlign.Right" Width="130"></GridColumn>
        <GridColumn Field=@nameof(Order.Freight) HeaderText="Freight" Format="C2" TextAlign="TextAlign.Right" Width="120"></GridColumn>
        <GridColumn Field="@nameof(Order.Verified)" DisplayAsCheckBox="true" Width="70"></GridColumn>
    </GridColumns>
    <GridEvents TValue="Order" RowSelected="OnRowSelected"></GridEvents>
</SfGrid>


@code {
    SfGrid<Order> grid { get; set; }
    public List<Order> Orders { get; set; }
    Order SelectedOrder = new Order { };

    protected override void OnInitialized()
    {
        Orders = Enumerable.Range(1, 75).Select(x => new Order()
        {
            OrderID = 1000 + x,
            CustomerID = (new string[] { "ALFKI", "ANANTR", "ANTON", "BLONP", "BOLID" })[new Random().Next(5)],
            Freight = 2.1 * x,
            OrderDate = DateTime.Now.AddDays(-x),
            Verified = (new bool[] { true, false })[new Random().Next(2)]
        }).ToList();
    }

    private void OnRowSelected(RowSelectEventArgs<Order> args)
    {
        args.PreventRender = true; //without this, you may see noticable delay in selection with 75 rows in grid.
        SelectedOrder = args.Data;
    }

    public class Order
    {
        public int? OrderID { get; set; }
        public string CustomerID { get; set; }
        public DateTime? OrderDate { get; set; }
        public double? Freight { get; set; }
        public bool Verified { get; set; }
    }
}

Note:

  • The PreventRender property internally overrides the ShouldRender method of the grid to prevent rendering.
  • It is recommended to set PreventRender to true for user interaction events such as RowSelected, RowSelecting, etc., for better performance.
  • For events without any argument, such as DataBound, you can use the PreventRender method to disable rendering.

Performance metrics

The following metrics were taken after rendering 5,000 records with 100 records per page with pagination.

Grid actionImprovement in Volume 3 as compared to Volume 2 (using .NET 5)
Initial load~+10%
Sorting~+75%
Filtering~+75%
Clear filtering~+70%
Paging~+75%
Selection~+95%
Column chooser~+73%
Column menu~+77%
Column resizing~+92%

Blazor DataGrid renders each row and cell as an individual component. Loading large numbers of rows and cells in the view will have a performance impact on both memory consumption and CPU processing.

To use a grid without such performance impacts, you can load a reduced set of rows in the grid using paging and virtualization features.

Note: Even with the paging or virtualization feature enabled, having hundreds of rows in a single grid page will lead to performance lag in an application. So, you need to set a reasonable page size in that scenario.

Conclusion

Thanks for reading! In this blog, we talked about the Blazor DataGrid’s performance improvements in WebAssembly apps in the 2020 Volume 3 release. This is done by avoiding rendering unnecessary components. Try them out and leave your feedback in the comments section below.

For existing customers, the newest version of Essential Studio® is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to check out our available features.

You can also contact us through our support forum, Direct-Trac, or feedback portal. We are always happy to assist you!

Be the first to get updates

Maithiliy K

Meet the Author

Maithiliy K

Maithiliy is a Product Manager for web components at Syncfusion. She has 9 years of experience in developing software components and has started her career in Syncfusion in 2010. She is an expert in providing solutions for web products related requirements.