chore: Improve Table, List load more threshold, and avoid duplicate request. (#550)

- Default `threshold` changed to 20.
This commit is contained in:
Jason Lee 2025-01-17 11:25:41 +08:00 committed by GitHub
parent 0312e47554
commit 04d720f3a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 40 deletions

View file

@ -1,4 +1,3 @@
use std::ops::Range;
use std::time::Duration;
use std::{cell::Cell, rc::Rc};
@ -95,10 +94,11 @@ pub trait ListDelegate: Sized + 'static {
/// Returns a threshold value (n rows), of course, when scrolling to the bottom,
/// the remaining number of rows triggers `load_more`.
/// This should smaller than the total number of first load rows.
///
/// Default: 50 rows
/// Default: 20 rows
fn load_more_threshold(&self) -> usize {
50
20
}
/// Load more data when the table is scrolled to the bottom.
@ -126,6 +126,7 @@ pub struct List<D: ListDelegate> {
selected_index: Option<usize>,
right_clicked_index: Option<usize>,
_search_task: Task<()>,
_load_more_task: Task<()>,
}
impl<D> List<D>
@ -160,6 +161,7 @@ where
loading: false,
size: Size::default(),
_search_task: Task::ready(()),
_load_more_task: Task::ready(()),
}
}
@ -323,27 +325,26 @@ where
}
/// Dispatch delegate's `load_more` method when the visible range is near the end.
fn load_more_if_need(&mut self, visible_range: Range<usize>, cx: &mut ViewContext<Self>) {
if !self.delegate.can_load_more(cx) {
return;
}
let items_count = self.delegate.items_count(cx);
fn load_more_if_need(
&mut self,
items_count: usize,
visible_end: usize,
cx: &mut ViewContext<Self>,
) {
let threshold = self.delegate.load_more_threshold();
if items_count < threshold {
return;
}
// Securely handle subtract logic to prevent attempt to subtract with overflow
if visible_range.end >= items_count - threshold {
cx.spawn(|view, mut cx| async move {
cx.update(|cx| {
if visible_end >= items_count.saturating_sub(threshold) {
if !self.delegate.can_load_more(cx) {
return;
}
self._load_more_task = cx.spawn(|view, mut cx| async move {
_ = cx.update(|cx| {
view.update(cx, |view, cx| {
view.delegate.load_more(cx);
})
})
})
.detach()
});
});
}
}
@ -525,7 +526,8 @@ where
uniform_list(view, "uniform-list", items_count, {
move |list, visible_range, cx| {
list.load_more_if_need(
visible_range.clone(),
items_count,
visible_range.end,
cx,
);

View file

@ -15,7 +15,7 @@ use gpui::{
DragMoveEvent, Edges, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
InteractiveElement, IntoElement, KeyBinding, ListSizingBehavior, MouseButton, MouseDownEvent,
ParentElement, Pixels, Point, Render, ScrollHandle, ScrollStrategy, SharedString, Stateful,
StatefulInteractiveElement as _, Styled, UniformListScrollHandle, ViewContext,
StatefulInteractiveElement as _, Styled, Task, UniformListScrollHandle, ViewContext,
VisualContext as _, WindowContext,
};
@ -176,6 +176,8 @@ pub struct Table<D: TableDelegate> {
visible_range: VisibleRangeState,
/// The loading state of the table.
loading: bool,
_load_more_task: Task<()>,
}
#[allow(unused)]
@ -297,10 +299,11 @@ pub trait TableDelegate: Sized + 'static {
/// Returns a threshold value (n rows), of course, when scrolling to the bottom,
/// the remaining number of rows triggers `load_more`.
/// This should smaller than the total number of first load rows.
///
/// Default: 50 rows
/// Default: 20 rows
fn load_more_threshold(&self) -> usize {
50
20
}
/// Load more data when the table is scrolled to the bottom.
@ -371,6 +374,7 @@ where
scrollbar_visible: Edges::all(true),
visible_range: VisibleRangeState::default(),
loading: false,
_load_more_task: Task::ready(()),
};
this.prepare_col_groups(cx);
@ -691,27 +695,26 @@ where
}
/// Dispatch delegate's `load_more` method when the visible range is near the end.
fn load_more_if_need(&mut self, visible_range: Range<usize>, cx: &mut ViewContext<Self>) {
if !self.delegate.can_load_more(cx) {
return;
}
let row_count = self.delegate.rows_count(cx);
fn load_more_if_need(
&mut self,
rows_count: usize,
visible_end: usize,
cx: &mut ViewContext<Self>,
) {
let threshold = self.delegate.load_more_threshold();
if row_count < threshold {
return;
}
// Securely handle subtract logic to prevent attempt to subtract with overflow
if visible_range.end >= row_count - threshold {
cx.spawn(|view, mut cx| async move {
cx.update(|cx| {
if visible_end >= rows_count.saturating_sub(threshold) {
if !self.delegate.can_load_more(cx) {
return;
}
self._load_more_task = cx.spawn(|view, mut cx| async move {
_ = cx.update(|cx| {
view.update(cx, |view, cx| {
view.delegate.load_more(cx);
})
})
})
.detach()
});
});
}
}
@ -1345,7 +1348,7 @@ where
rows_count + extra_rows_needed,
{
move |table, visible_range, cx| {
table.load_more_if_need(visible_range.clone(), cx);
table.load_more_if_need(rows_count, visible_range.end, cx);
table.update_visible_range_if_need(
visible_range.clone(),
Axis::Vertical,