fix(chat): apply loadMessages dedup to force=true callers as well

useWebSocket's ready handler calls loadMessages(channelId, true) from
two adjacent code paths in the same handler invocation (remote-space
refresh + per-origin cache clearing). Both fired in parallel because
force=true bypassed dedup, producing the duplicate /messages requests
visible in playwright network traces even after the parallel-mount
dedup landed.

Coalescing force=true with an in-flight call is safe: the requests hit
the same endpoint with the same params and would return the same data,
and the force caller still gets a fresh result via the shared Promise.
This commit is contained in:
Jannis Braun
2026-05-05 20:52:05 +02:00
parent a189cbfba3
commit 40c27ed90f
+10 -6
View File
@@ -179,12 +179,16 @@ export const useChatStore = create<ChatState>((set, get) => ({
// The remote WS ready handler will call loadMessages once the map is populated. // The remote WS ready handler will call loadMessages once the map is populated.
if (!isDm && !useSpaceStore.getState().channelOriginMap.has(channelId)) return; if (!isDm && !useSpaceStore.getState().channelOriginMap.has(channelId)) return;
// Parallel-call dedup: if a non-forced load for this channel is already in // Parallel-call dedup: if a load for this channel is already in flight,
// flight, return that Promise instead of starting a second fetch. `force` // return that Promise instead of starting a second fetch. Applies to
// bypasses the dedup because callers using it (WS reconnect) explicitly // force=true callers as well — `useWebSocket`'s ready handler invokes
// want a fresh fetch even if one is already pending. See `inFlightLoads` // `loadMessages(currentChannelId, true)` from two adjacent code paths
// declaration for the full rationale. // (one for remote-instance space refresh, one for cache clearing) on every
if (!force) { // WS-ready event, and there's no value in two parallel fetches for the
// same channel: they hit the same endpoint with the same params and
// return the same data. Coalescing is safe; the force caller still gets a
// fresh result via the in-flight Promise.
{
const existing = inFlightLoads.get(channelId); const existing = inFlightLoads.get(channelId);
if (existing) return existing; if (existing) return existing;
} }