这最终变成了一个棘手的“竞态条件”,发生在用于检测何时需要触发“加载更多”操作的“哨兵”与用户目录中行的渲染之间 ![]()
问题
当用户数量至少为 50 时,“/u”(用户目录)页面会在用户向下滚动之前立即触发 loadMore。这会导致意外地自动加载第二页结果。
根本原因
初始页面加载期间的竞态条件:
- 用户导航到
/u controllers/users开始加载数据 (isLoading: true)- 模板渲染
ConditionalLoadingSpinner并显示加载指示器 - 数据到达,
isLoading变为false - 加载指示器隐藏,
DirectoryTable开始渲染 50 个用户 LoadMore哨兵元素插入 DOMIntersectionObserver被创建并立即开始观察- 此时,表格仍在计算布局/扩展到完整高度
- 在表格扩展之前,哨兵短暂地出现在视口中(距离顶部约 292px)
- 观察者检测到交叉 → 触发
loadMore
- 表格完成扩展到完整高度(约 3689px)
- 哨兵移动到正确位置(约 3959px,视口下方)
观察者“过于积极”——它在内容完成布局之前就开始观察,在表格尚未达到最终高度的短暂时刻捕获了哨兵。
修复
延迟创建观察者,直到内容准备就绪:
向 LoadMore 添加了一个 @isLoading 参数,当内容仍在加载时,该参数会阻止创建 IntersectionObserver。
现在的工作方式
页面加载 → isLoading=true → Modifier 跳过观察者创建
↓
数据加载 → isLoading=false → Modifier 重新运行,创建观察者
↓
表格完全展开 → 哨兵位于正确位置(视口下方)
↓
用户向下滚动 → 哨兵进入视口 → loadMore 触发 ✓