@inject IJSRuntime JS @inject State State @implements IDisposable @if (Editable) { } @if (pics != null) foreach (Pic pic in pics) { } @code { [Parameter] public Func?>> PicsFunc { get; set; } [Parameter] public bool Editable { get; set; } = false; public EditPicDialog? Dialog { get; set; } private List? pics; private int count { get; set; } = 0; private int pageSize { get; } = 10; // TODO: There is a noticable rendering delay between the pics loading and the page rendering protected override async Task OnInitializedAsync() { await base.OnInitializedAsync(); State.PropertyChanged += StateChanged; State.CanRefresh = true; if (pics == null || pics.Count == 0) await LoadNext(); await JS.InvokeVoidAsync("removeElementById", "pics-loading"); } public async Task PullUp() { int countBefore = count; await LoadNext(); return (count != countBefore); } public async Task LoadNext(bool forceRefresh = false) { if (pics == null) pics = new List(); if (forceRefresh) { count = 0; pics.Clear(); } var allPics = await PicsFunc(forceRefresh); if(allPics != null && count < allPics.Count) { pics.AddRange(allPics.Skip(count).Take(pageSize)); count = pics.Count; } await InvokeAsync(StateHasChanged); } private async void StateChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(State.IsRefreshing) && State.IsRefreshing) { await LoadNext(true); State.IsRefreshing = false; } if (e.PropertyName == nameof(State.AtBottom) && State.AtBottom) { await LoadNext(); } } public void Dispose() { State.PropertyChanged -= StateChanged; State.CanRefresh = false; } }