From 435051ddc884ff2338bdabadb3acbb44f1dfb6f4 Mon Sep 17 00:00:00 2001 From: lorentz Date: Thu, 7 May 2026 23:01:22 -0400 Subject: [PATCH] fix(08-02): retry scroll restoration across frames until layout finalizes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The window scrolls (not
) on this layout, and the document content height isn't fully laid out by the first rAF after rows render — so window.scrollTo gets clamped to maxScroll, leaving the user near top. Retry up to 30 frames (~500ms) until the actual scroll position matches the target within 4px. --- app/mobile/engagement/page.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/app/mobile/engagement/page.tsx b/app/mobile/engagement/page.tsx index 80c7093..4170f0c 100644 --- a/app/mobile/engagement/page.tsx +++ b/app/mobile/engagement/page.tsx @@ -205,12 +205,24 @@ export default function MobileEngagementPage() { if (!raw) { restoredScrollRef.current = true; return; } try { const { main: mainTop, win: winTop } = JSON.parse(raw) as { main: number; win: number }; - // Defer one frame so layout has settled with the new rows in place. - requestAnimationFrame(() => { + // Retry across frames until document height supports the target scroll; + // initial render may compute heights lazily and clamp scrollTo to a small + // maxScroll. Cap attempts so we never loop forever. + let attempts = 0; + const tryRestore = () => { const main = document.querySelector('main'); if (main && mainTop) main.scrollTop = mainTop; if (winTop) window.scrollTo(0, winTop); - }); + const winNow = window.scrollY; + const mainNow = main?.scrollTop ?? 0; + const winOk = !winTop || Math.abs(winNow - winTop) <= 4; + const mainOk = !mainTop || Math.abs(mainNow - mainTop) <= 4; + if ((!winOk || !mainOk) && attempts < 30) { + attempts++; + requestAnimationFrame(tryRestore); + } + }; + requestAnimationFrame(tryRestore); } catch { /* corrupt entry — ignore */ }