From 648cea698d5c5e74853cc9d059c906666e6ef41e Mon Sep 17 00:00:00 2001 From: simoleo89 Date: Sat, 13 Jun 2026 16:20:59 +0200 Subject: [PATCH] fix(room): word-quiz countdown mutates Map value objects in place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1s tick did `value.secondsLeft--` on the VoteValue objects held by the previous state Map and returned the same Map reference when nothing expired — an in-place state mutation (breaks memoization / StrictMode double-invoke). Rebuild new value objects in a new Map each tick (and drop expired entries). --- src/hooks/rooms/widgets/useWordQuizWidget.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/hooks/rooms/widgets/useWordQuizWidget.ts b/src/hooks/rooms/widgets/useWordQuizWidget.ts index bb48327..aef3cf6 100644 --- a/src/hooks/rooms/widgets/useWordQuizWidget.ts +++ b/src/hooks/rooms/widgets/useWordQuizWidget.ts @@ -112,19 +112,21 @@ const useWordQuizWidgetState = () => { setUserAnswers(prevValue => { - const keysToRemove: number[] = []; + if(prevValue.size === 0) return prevValue; - prevValue.forEach((value, key) => + // Build new value objects + a new Map — don't decrement + // secondsLeft on the objects still referenced by prevValue + // (in-place mutation breaks memoization / StrictMode replay). + const next = new Map(prevValue); + + next.forEach((value, key) => { - value.secondsLeft--; + const secondsLeft = value.secondsLeft - 1; - if(value.secondsLeft <= 0) keysToRemove.push(key); + if(secondsLeft <= 0) next.delete(key); + else next.set(key, { ...value, secondsLeft }); }); - if(keysToRemove.length === 0) return prevValue; - - const next = new Map(prevValue); - keysToRemove.forEach(key => next.delete(key)); return next; }); };