Read-position recompute walks all joined members and re-renders the whole timeline #40

Closed
opened 2026-09-12 01:51:08 -04:00 by jared · 0 comments
Owner

Severity: medium · Type: performance · Confidence: high

Location: src/app/hooks/useRoomReadPositions.ts:21-64, src/app/features/room/RoomTimeline.tsx:466,2131

Problem

Every RoomEvent.Receipt (debounced 150 ms) calls computePositions, which iterates room.getJoinedMembers() and calls room.getEventReadUpTo per member on top of an O(timeline) index build, then sets a new Map as state. That map is the ReadPositionsContext value, so every Message in the rendered window re-renders — regardless of whether its receipts changed. In a large, active room receipts arrive continuously, giving a full timeline re-render every 150 ms.

How to trigger

Open a room with a few hundred active members and watch React DevTools while others read.

Suggested fix

Diff against the previous map and reuse the old reference (and old per-event arrays) when unchanged, and/or move the per-message lookup to a useSyncExternalStore-style subscription keyed by event id so only affected rows re-render.


Filed from the September 2026 client audit (branch lotus @ 4bea4895).

**Severity:** medium · **Type:** performance · **Confidence:** high **Location:** `src/app/hooks/useRoomReadPositions.ts:21-64`, `src/app/features/room/RoomTimeline.tsx:466,2131` ### Problem Every `RoomEvent.Receipt` (debounced 150 ms) calls `computePositions`, which iterates `room.getJoinedMembers()` and calls `room.getEventReadUpTo` per member on top of an O(timeline) index build, then sets a **new `Map`** as state. That map is the `ReadPositionsContext` value, so every `Message` in the rendered window re-renders — regardless of whether its receipts changed. In a large, active room receipts arrive continuously, giving a full timeline re-render every 150 ms. ### How to trigger Open a room with a few hundred active members and watch React DevTools while others read. ### Suggested fix Diff against the previous map and reuse the old reference (and old per-event arrays) when unchanged, and/or move the per-message lookup to a `useSyncExternalStore`-style subscription keyed by event id so only affected rows re-render. --- _Filed from the September 2026 client audit (branch `lotus` @ 4bea4895)._
jared added this to the Audit 2026-09 · Medium & Low milestone 2026-09-12 01:51:08 -04:00
jared added the bugpriority: mediumperformancearea: messaging labels 2026-09-12 01:51:08 -04:00
jared self-assigned this 2026-09-12 01:51:08 -04:00
jared closed this issue 2026-09-15 21:32:09 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
2026-11-14
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#40