Skip to content

Commit cff448e

Browse files
StevenTCramerdvoituronvnbaaij
authored andcommitted
[DataGrid] Improve data refresh logic (microsoft#2512)
* Improve data refresh logic in FluentDataGrid This commit enhances the OnParametersSetAsync method in FluentDataGrid to better handle state changes: - Updated mustRefreshData calculation to consider pagination state changes - Moved _lastRefreshedPaginationStateHash update earlier in RefreshDataCoreAsync These changes ensure that: 1. The grid correctly detects when a refresh is needed due to pagination changes 2. The pagination state hash is captured at the start of the refresh process This improvement helps maintain data consistency, especially in scenarios with rapid state changes or when other events trigger state updates. * Fix Grid data source change detection to avoid boxing - Replace object casting and reference comparison with direct Equals method calls - Separately compare Items and ItemsProvider with their last assigned values - Eliminate false positive change detections caused by boxing - Improve performance by reducing unnecessary data refreshes * Don't use GetHashCode for comparison. TotalCount should NOT be a part of the comparison. As this is an output not an input. * use _lastRefreshedPaginationState instead of _lastRefreshedPaginationStateHash * Remove blank line --------- Co-authored-by: Denis Voituron <[email protected]> Co-authored-by: Vincent Baaij <[email protected]>
1 parent 982a088 commit cff448e

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

src/Core/Components/DataGrid/FluentDataGrid.razor.cs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public partial class FluentDataGrid<TGridItem> : FluentComponentBase, IHandleEve
226226
// This happens on every render so that the column list can be updated dynamically
227227
private readonly InternalGridContext<TGridItem> _internalGridContext;
228228
internal readonly List<ColumnBase<TGridItem>> _columns;
229-
private bool _collectingColumns; // Columns might re-render themselves arbitrarily. We only want to capture them at a defined time.
229+
private bool _collectingColumns;// Columns might re-render themselves arbitrarily. We only want to capture them at a defined time.
230230

231231
// Tracking state for options and sorting
232232
private ColumnBase<TGridItem>? _displayOptionsForColumn;
@@ -252,8 +252,9 @@ public partial class FluentDataGrid<TGridItem> : FluentComponentBase, IHandleEve
252252
// We only re-query when the developer calls RefreshDataAsync, or if we know something's changed, such
253253
// as sort order, the pagination state, or the data source itself. These fields help us detect when
254254
// things have changed, and to discard earlier load attempts that were superseded.
255-
private int? _lastRefreshedPaginationStateHash;
256-
private object? _lastAssignedItemsOrProvider;
255+
private PaginationState? _lastRefreshedPaginationState;
256+
private IQueryable<TGridItem>? _lastAssignedItems;
257+
private GridItemsProvider<TGridItem>? _lastAssignedItemsProvider;
257258
private CancellationTokenSource? _pendingDataLoadCancellationTokenSource;
258259

259260
// If the PaginationState mutates, it raises this event. We use it to trigger a re-render.
@@ -303,16 +304,19 @@ protected override Task OnParametersSetAsync()
303304
}
304305

305306
// Perform a re-query only if the data source or something else has changed
306-
var _newItemsOrItemsProvider = Items ?? (object?)ItemsProvider;
307-
var dataSourceHasChanged = _newItemsOrItemsProvider != _lastAssignedItemsOrProvider;
307+
var dataSourceHasChanged = !Equals(Items, _lastAssignedItems) || !Equals(ItemsProvider, _lastAssignedItemsProvider);
308308
if (dataSourceHasChanged)
309309
{
310-
_lastAssignedItemsOrProvider = _newItemsOrItemsProvider;
310+
_lastAssignedItemsProvider = ItemsProvider;
311+
_lastAssignedItems = Items;
311312
_asyncQueryExecutor = AsyncQueryExecutorSupplier.GetAsyncQueryExecutor(Services, Items);
312313
}
313314

314-
var mustRefreshData = dataSourceHasChanged
315-
|| (Pagination?.GetHashCode() != _lastRefreshedPaginationStateHash);
315+
var paginationStateHasChanged =
316+
Pagination?.ItemsPerPage != _lastRefreshedPaginationState?.ItemsPerPage
317+
|| Pagination?.CurrentPageIndex != _lastRefreshedPaginationState?.CurrentPageIndex;
318+
319+
var mustRefreshData = dataSourceHasChanged || paginationStateHasChanged;
316320

317321
// We don't want to trigger the first data load until we've collected the initial set of columns,
318322
// because they might perform some action like setting the default sort order, so it would be wasteful
@@ -506,6 +510,7 @@ private async Task RefreshDataCoreAsync()
506510
var startIndex = Pagination is null ? 0 : (Pagination.CurrentPageIndex * Pagination.ItemsPerPage);
507511
GridItemsProviderRequest<TGridItem> request = new(
508512
startIndex, Pagination?.ItemsPerPage, _sortByColumn, _sortByAscending, thisLoadCts.Token);
513+
_lastRefreshedPaginationState = Pagination;
509514
var result = await ResolveItemsRequestAsync(request);
510515
if (!thisLoadCts.IsCancellationRequested)
511516
{
@@ -515,7 +520,6 @@ private async Task RefreshDataCoreAsync()
515520
_pendingDataLoadCancellationTokenSource = null;
516521
}
517522
_internalGridContext.ResetRowIndexes(startIndex);
518-
_lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
519523
}
520524

521525
StateHasChanged();
@@ -524,7 +528,7 @@ private async Task RefreshDataCoreAsync()
524528
// Gets called both by RefreshDataCoreAsync and directly by the Virtualize child component during scrolling
525529
private async ValueTask<ItemsProviderResult<(int, TGridItem)>> ProvideVirtualizedItemsAsync(ItemsProviderRequest request)
526530
{
527-
_lastRefreshedPaginationStateHash = Pagination?.GetHashCode();
531+
_lastRefreshedPaginationState = Pagination;
528532

529533
// Debounce the requests. This eliminates a lot of redundant queries at the cost of slight lag after interactions.
530534
// TODO: Consider making this configurable, or smarter (e.g., doesn't delay on first call in a batch, then the amount

0 commit comments

Comments
 (0)