fix(call): rAF batch flush never emptied into state

The real reason every thumbnail card stayed on the placeholder was a
reference-aliasing bug in the flush closure. `const batch = pendingUrls`
captured the same object; `delete (pendingUrls)[k]` for each key then
emptied `batch` too, because they were the same reference. By the time
`setThumbnailUrls(prev => ({ ...prev, ...batch }))` ran, batch was {}
and the state never picked up any URL — every card rendered the empty
placeholder icon.

Fixed by aliasing first, then replacing pendingUrls with a fresh empty
object (let instead of const on the outer binding). The cloned `batch`
retains its entries for the spread; any new arrivals during the commit
land in the new empty pendingUrls and coalesce into the next frame.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
byGalax
2026-04-22 22:26:45 +02:00
parent 6c6a23e672
commit e2e8217b86
@@ -79,16 +79,18 @@ export function ScreenSourcePicker({ open, onClose, onStart }: Props) {
// one setState — cuts re-renders from O(N) to O(frames) during the
// initial fan-in and prevents consecutive 10-30 ms long tasks from
// stacking in one frame.
const pendingUrls: Record<string, string> = {};
//
// Previously `batch` was aliased to `pendingUrls` and then we cleared
// pendingUrls via `delete` — which emptied batch too (same reference)
// and every flush ended up spreading nothing into the state. Clone
// first, then clear, so the batch keeps its entries.
let pendingUrls: Record<string, string> = {};
let rafScheduled = false;
const flush = () => {
rafScheduled = false;
if (Object.keys(pendingUrls).length === 0) return;
const batch = pendingUrls;
// Capture then reset so new arrivals during the commit land in a
// fresh batch instead of double-applying.
const keys = Object.keys(batch);
for (const k of keys) delete (pendingUrls as Record<string, string>)[k];
if (Object.keys(batch).length === 0) return;
pendingUrls = {};
startTransition(() => {
setThumbnailUrls((prev) => ({ ...prev, ...batch }));
});