diff options
| author | Adam Soltys <[email protected]> | 2026-09-26 23:21:27 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-09-26 23:21:27 -0700 |
| commit | b9226f695c827a4b16719fd0c752801f4e768e6c (patch) | |
| tree | 85b42fa9e7e135063af1fbfdfb4f0eabb5c0879a /src/app.js | |
| parent | dbf755968827b0d75f5e30d35a6c90da3cdc1aa2 (diff) | |
| download | coinosv3-b9226f695c827a4b16719fd0c752801f4e768e6c.tar.gz coinosv3-b9226f695c827a4b16719fd0c752801f4e768e6c.zip | |
Keyed morph: drop stale nodes before placing survivors, so a repaint moves nothing.
With stale nodes still in front, every kept row's position was off by the
stale count and each one was pulled out and re-inserted — a remove and an
add per row per repaint. The feed's window evicting rows at the top did
this to every mounted row on every scroll step; a moved <video> leaves the
document and comes back, restarting its loading (one clip was fetched 61
times in 40 seconds), and images were refetched. Measured with a
MutationObserver on the live tab: 160 of 179 row additions during a
20-second scroll were the same key going out and back in.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 12 |
1 files changed, 12 insertions, 0 deletions
@@ -271,6 +271,18 @@ const allKeyed = (nodes) => nodes.length > 0 function morphKeyed(parent, cur, next) { const byKey = new Map(); for (const n of cur) if (n.nodeType === 1 && n.hasAttribute('data-key')) byKey.set(n.getAttribute('data-key'), n); + // Drop what the new render no longer has BEFORE placing the rest: with + // stale nodes still in front, every survivor's position was off by the + // stale count and each one was pulled out and re-inserted — a move per row + // per repaint (the feed's window evicting rows at the top did this to all + // the rows below on every scroll), and a moved <video> is taken out of + // the document and back, which restarts its loading. + const wanted = new Set(next.map((b) => b.getAttribute('data-key'))); + for (const n of cur) { + if (n.parentNode !== parent) continue; + const k = n.nodeType === 1 ? n.getAttribute('data-key') : null; + if (k == null || !wanted.has(k)) n.remove(); + } const kept = new Set(); for (let i = 0; i < next.length; i++) { const b = next[i]; |
