Skip to content

fix: restore virtualized list scroll positions - #657

Merged
hmjn023 merged 2 commits into
developfrom
fix/virtual-scroll-restoration
Aug 2, 2026
Merged

fix: restore virtualized list scroll positions#657
hmjn023 merged 2 commits into
developfrom
fix/virtual-scroll-restoration

Conversation

@hmjn023

@hmjn023 hmjn023 commented Aug 2, 2026

Copy link
Copy Markdown
Owner

概要

検索画面とsourceメディア一覧で、個別画面などへ遷移して戻った際のスクロール位置復元を仮想スクロール対応にします。

変更内容

  • windowスクロールと内部の data-media-scroll コンテナで共通の復元処理を追加
  • 保存位置まで現在のグリッド高さが足りない場合、次チャンクを先読みしてから復元
  • 検索状態・source IDごとの位置保存を維持
  • 新しい検索実行時は保存位置を先頭へリセット
  • ユーザー操作中や画面破棄後の復元処理をキャンセル

検証

  • packages/ui typecheck
  • packages/ui tests: 57 passed
  • apps/server typecheck
  • 仮想グリッドE2E: 4 passed

route-reload E2Eは既存のSSR側 template is not a function エラーにより実行時エラーとなります。

Summary by CodeRabbit

  • 新機能

    • ページ遷移後にスクロール位置を自動復元できるようになりました。
    • 保存位置まで追加データを取得してから復元し、取得失敗時や上限到達時も可能な位置で復元します。
    • 復元中のユーザー操作によるキャンセルに対応しました。
    • ウィンドウおよびスクロールコンテナの位置復元に対応しました。
  • 改善

    • 検索結果ページやソースメディアページで、スクロール位置の保存・復元が安定しました。
    • 検索条件の変更時はスクロール位置が先頭に戻ります。

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 13e561ff-4316-433d-8f79-5fdd3f8acba0

📥 Commits

Reviewing files that changed from the base of the PR and between 340d3b9 and e5d9cd5.

📒 Files selected for processing (1)
  • packages/ui/src/hooks/scroll-container.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/ui/src/hooks/scroll-container.ts

📝 Walkthrough

Walkthrough

スクロール位置の保存・復元処理を useScrollRestoration へ集約しました。未ロード範囲の追加取得、復元中の操作キャンセル、ライフサイクルのクリーンアップを実装し、検索ページとソースメディアページで利用します。

Changes

スクロール位置復元

Layer / File(s) Summary
復元フックの実装
packages/ui/src/hooks/scroll-container.ts
ScrollRestorationOptionsuseScrollRestoration を追加しました。保存位置の測定、ページ追加取得、位置のクランプ、操作によるキャンセル、タイマーとイベントのクリーンアップを実装しました。
検索ページへの移行
packages/ui/src/hooks/use-search-page.ts
手動の復元・保存処理を削除しました。復元キー、準備状態、ページ取得状態、スクロールコンテナを useScrollRestoration に渡します。
ソースメディアページへの移行
packages/ui/src/hooks/use-source-media-page.ts
ソース変更時に保存位置を 0 に設定します。手動の復元、履歴設定、遅延処理、アンマウント処理を useScrollRestoration へ移しました。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PageHook as ページフック
  participant Restoration as useScrollRestoration
  participant FetchNextPage as fetchNextPage
  participant ScrollContainer as スクロールコンテナ
  PageHook->>Restoration: 復元キー、準備状態、ページ取得状態を渡す
  Restoration->>ScrollContainer: 現在の最大位置を測定
  Restoration->>FetchNextPage: 保存位置が未ロード範囲なら追加取得
  FetchNextPage-->>Restoration: 取得状態を更新
  Restoration->>ScrollContainer: 保存位置までスクロール
  ScrollContainer-->>Restoration: ユーザー操作で復元をキャンセル
Loading

Possibly related PRs

  • hmjn023/solid-imager#598: use-search-page.tsuse-source-media-page.ts のページフックおよび復元状態処理に関連します。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは、仮想化リストのスクロール位置を復元する主要な変更を簡潔かつ正確に示しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/virtual-scroll-restoration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/ui/src/hooks/scroll-container.ts (2)

129-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

同期的な世代比較は常に成立します。

Line 131 で generationrestoreGeneration を代入します。Line 138 の generation !== restoreGeneration は同じ同期ブロック内の比較です。この条件は常に false です。ガードとして機能しません。

await の後で世代を検証する意図であれば、Line 168 の検証のみが有効です。Line 138 の条件は削除してください。

♻️ 提案する修正
 	const attemptRestore = async () => {
 		const key = activeKey;
 		const generation = restoreGeneration;
 		if (
 			!key ||
 			cancelled ||
 			isRestored() ||
 			settleTimer !== undefined ||
-			!options.isReady() ||
-			generation !== restoreGeneration
+			!options.isReady()
 		) {
 			return;
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/hooks/scroll-container.ts` around lines 129 - 141, Remove the
ineffective generation !== restoreGeneration guard from attemptRestore’s initial
synchronous condition; retain the later generation validation after the await,
where restoreGeneration may have changed.

209-212: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

history.scrollRestoration を元の値に戻していません。

このフックは history.scrollRestoration"manual" に変更します。onCleanup で元の値に戻しません。history はグローバルな状態です。このフックを使わない他のページへ遷移した後も、ブラウザの自動スクロール復元は無効のままです。

元の値を保存し、cleanup で復帰させてください。

♻️ 提案する修正
 	onMount(() => {
+		const previousScrollRestoration =
+			"scrollRestoration" in history ? history.scrollRestoration : undefined;
 		if ("scrollRestoration" in history) {
 			history.scrollRestoration = "manual";
 		}
@@
 		onCleanup(() => {
+			if (previousScrollRestoration !== undefined) {
+				history.scrollRestoration = previousScrollRestoration;
+			}
 			window.removeEventListener("pointerdown", cancelRestore);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/hooks/scroll-container.ts` around lines 209 - 212, In the
onMount callback, save the existing history.scrollRestoration value before
setting it to "manual", and register an onCleanup handler that restores that
saved value. Keep the history feature check and existing scroll-container
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/ui/src/hooks/scroll-container.ts`:
- Around line 178-184:
復元完了前の現在位置保存を防ぐため、packages/ui/src/hooks/scroll-container.ts の178-184行にある
savePosition の先頭で isRestored() を確認し、未完了なら即時 return
してください。packages/ui/src/hooks/use-source-media-page.ts の302-312行の
setPosition/setScrollPosition
は直接変更せず、修正後にソース切替から元のソースへ戻った際に保存済み位置が保持されることを確認してください。

---

Nitpick comments:
In `@packages/ui/src/hooks/scroll-container.ts`:
- Around line 129-141: Remove the ineffective generation !== restoreGeneration
guard from attemptRestore’s initial synchronous condition; retain the later
generation validation after the await, where restoreGeneration may have changed.
- Around line 209-212: In the onMount callback, save the existing
history.scrollRestoration value before setting it to "manual", and register an
onCleanup handler that restores that saved value. Keep the history feature check
and existing scroll-container behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b75f9aa7-5e4c-4e3b-b117-73d53b7d2d63

📥 Commits

Reviewing files that changed from the base of the PR and between 2b4f8d8 and 340d3b9.

📒 Files selected for processing (3)
  • packages/ui/src/hooks/scroll-container.ts
  • packages/ui/src/hooks/use-search-page.ts
  • packages/ui/src/hooks/use-source-media-page.ts

Comment thread packages/ui/src/hooks/scroll-container.ts
@hmjn023
hmjn023 merged commit 16665b2 into develop Aug 2, 2026
1 check passed
@hmjn023
hmjn023 deleted the fix/virtual-scroll-restoration branch August 2, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant