fix: v0.19.4 生成页往上翻加载历史时不再跳到底部
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m15s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m15s
现象: 用户往上翻看历史, loadMore 往 tasks 数组头部 prepend 老任务后, 页面自动跳到最底, 打断浏览。 根因 VideoGenerationPage.tsx useEffect 依赖 tasks.length, 只要数量 增加就 scrollTo(scrollHeight)。这个逻辑本意是"新任务生成 push 到 末尾时滚到底", 但区分不出"头部 prepend" vs "尾部 push", 于是 loadMore 也触发了滚底。handleScroll 里的 anchor(scrollTop += diff) 本来会做视觉保位, 但 useEffect 的 scrollTo smooth 抢先/盖过它。 修复 改成比末尾 task 的 id 是否变化 (prevLastIdRef) 而非 length - 新任务 push 到末尾 → 末尾 id 变 → 滚到底 ✅ - 头部加载历史 → 末尾 id 不变 → 保位置 ✅ - 轮询更新任务属性(如生成完成) → 数组内容变但末尾 id 不变 → 不打扰 ✅ - 删除某条任务(非末尾) → 末尾 id 不变 → 不滚 ✅ - 只有"末尾多了新东西"这一种情况才滚底, 符合用户直觉 验证 vitest 71 failed 全部为 v0.18.x 以来的 preexisting 失败 (phase2/phase3 路径解析问题), stash 前后对比完全一致, 本次改动 零新增回归。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ecdb9cb471
commit
10994df952
@ -20,7 +20,7 @@ export function VideoGenerationPage() {
|
||||
const regenerate = useGenerationStore((s) => s.regenerate);
|
||||
const removeTask = useGenerationStore((s) => s.removeTask);
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const prevCountRef = useRef(tasks.length);
|
||||
const prevLastIdRef = useRef<string | null>(null);
|
||||
const initialLoadRef = useRef(true);
|
||||
const savedScrollTop = useGenerationStore((s) => s.savedScrollTop);
|
||||
const saveScrollPosition = useGenerationStore((s) => s.saveScrollPosition);
|
||||
@ -36,9 +36,14 @@ export function VideoGenerationPage() {
|
||||
loadTasks();
|
||||
}, [loadTasks]);
|
||||
|
||||
// Restore scroll position after initial load, or scroll to bottom for new tasks
|
||||
// Restore scroll position after initial load, or scroll to bottom ONLY when a new task
|
||||
// is appended at the tail. 通过比较末尾 task 的 id 来判断 —— 头部加载历史(prepend)、
|
||||
// 任务状态更新(如轮询完成)、删除某条都不会改变末尾 id,因此不会触发滚动,
|
||||
// 避免用户往上翻时被突然拽回底部。
|
||||
useEffect(() => {
|
||||
if (tasks.length === 0) return;
|
||||
const currentLastId = tasks[tasks.length - 1]?.id ?? null;
|
||||
|
||||
if (initialLoadRef.current) {
|
||||
initialLoadRef.current = false;
|
||||
// Use requestAnimationFrame to ensure DOM has rendered
|
||||
@ -50,15 +55,16 @@ export function VideoGenerationPage() {
|
||||
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
|
||||
}
|
||||
});
|
||||
prevCountRef.current = tasks.length;
|
||||
prevLastIdRef.current = currentLastId;
|
||||
return;
|
||||
}
|
||||
if (tasks.length > prevCountRef.current && scrollRef.current) {
|
||||
|
||||
if (currentLastId !== prevLastIdRef.current && scrollRef.current) {
|
||||
scrollRef.current.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' });
|
||||
}
|
||||
prevCountRef.current = tasks.length;
|
||||
prevLastIdRef.current = currentLastId;
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [tasks.length]);
|
||||
}, [tasks]);
|
||||
|
||||
// Save scroll position + auto-load older tasks when scrolled near top
|
||||
const handleScroll = useCallback(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user