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::time::Duration;
use std::{cell::Cell, rc::Rc}; 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, /// Returns a threshold value (n rows), of course, when scrolling to the bottom,
/// the remaining number of rows triggers `load_more`. /// 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 { fn load_more_threshold(&self) -> usize {
50 20
} }
/// Load more data when the table is scrolled to the bottom. /// Load more data when the table is scrolled to the bottom.
@ -126,6 +126,7 @@ pub struct List<D: ListDelegate> {
selected_index: Option<usize>, selected_index: Option<usize>,
right_clicked_index: Option<usize>, right_clicked_index: Option<usize>,
_search_task: Task<()>, _search_task: Task<()>,
_load_more_task: Task<()>,
} }
impl<D> List<D> impl<D> List<D>
@ -160,6 +161,7 @@ where
loading: false, loading: false,
size: Size::default(), size: Size::default(),
_search_task: Task::ready(()), _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. /// 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>) { fn load_more_if_need(
if !self.delegate.can_load_more(cx) { &mut self,
return; items_count: usize,
} visible_end: usize,
cx: &mut ViewContext<Self>,
let items_count = self.delegate.items_count(cx); ) {
let threshold = self.delegate.load_more_threshold(); let threshold = self.delegate.load_more_threshold();
if items_count < threshold {
return;
}
// Securely handle subtract logic to prevent attempt to subtract with overflow // Securely handle subtract logic to prevent attempt to subtract with overflow
if visible_range.end >= items_count - threshold { if visible_end >= items_count.saturating_sub(threshold) {
cx.spawn(|view, mut cx| async move { if !self.delegate.can_load_more(cx) {
cx.update(|cx| { return;
}
self._load_more_task = cx.spawn(|view, mut cx| async move {
_ = cx.update(|cx| {
view.update(cx, |view, cx| { view.update(cx, |view, cx| {
view.delegate.load_more(cx); view.delegate.load_more(cx);
}) })
}) });
}) });
.detach()
} }
} }
@ -525,7 +526,8 @@ where
uniform_list(view, "uniform-list", items_count, { uniform_list(view, "uniform-list", items_count, {
move |list, visible_range, cx| { move |list, visible_range, cx| {
list.load_more_if_need( list.load_more_if_need(
visible_range.clone(), items_count,
visible_range.end,
cx, cx,
); );

View file

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