Skip to content

Commit b4f50f3

Browse files
committed
simplify timer cleanup
1 parent 06dea14 commit b4f50f3

File tree

1 file changed

+11
-15
lines changed

1 file changed

+11
-15
lines changed

experiment/components/ChatPanel.tsx

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ export default function ChatPanel({ onNewMessage }: ChatPanelProps) {
6060
const [showTypingIndicator, setShowTypingIndicator] = useState(false);
6161
const [deliveredMessageIds, setDeliveredMessageIds] = useState<Set<string>>(new Set());
6262
const [readMessageIds, setReadMessageIds] = useState<Set<string>>(new Set());
63-
const deliveredTimersRef = useRef<NodeJS.Timeout[]>([]);
64-
const readTimersRef = useRef<NodeJS.Timeout[]>([]);
6563
const loggedMessagePartsRef = useRef<Set<string>>(new Set());
6664
const hasInitializedRef = useRef(false);
6765
const followupSentRef = useRef(false);
@@ -254,6 +252,8 @@ export default function ChatPanel({ onNewMessage }: ChatPanelProps) {
254252
// Track user messages for delivered/read status (uses useChat's message IDs for UI)
255253
const trackedUserMessageIdsRef = useRef<Set<string>>(new Set());
256254
useEffect(() => {
255+
const deliveredTimers: NodeJS.Timeout[] = [];
256+
const readTimers: NodeJS.Timeout[] = [];
257257
messages.forEach((message) => {
258258
if (message.role !== 'user' || !message.id || message.id === 'initial-user-message') return;
259259
if (trackedUserMessageIdsRef.current.has(message.id)) return;
@@ -264,15 +264,21 @@ export default function ChatPanel({ onNewMessage }: ChatPanelProps) {
264264
const deliveredTimer = setTimeout(() => {
265265
setDeliveredMessageIds((prev) => new Set(prev).add(message.id));
266266
}, deliveredDelay);
267-
deliveredTimersRef.current.push(deliveredTimer);
267+
deliveredTimers.push(deliveredTimer);
268268

269269
// Mark message as read after a short delay to feel more human
270270
const readDelay = 3000 + Math.random() * 5000; // 3-8 seconds
271271
const readTimer = setTimeout(() => {
272272
setReadMessageIds((prev) => new Set(prev).add(message.id));
273273
}, readDelay);
274-
readTimersRef.current.push(readTimer);
274+
readTimers.push(readTimer);
275275
});
276+
277+
// Cleanup the timers on unmount
278+
return () => {
279+
deliveredTimers.forEach((timer) => void clearTimeout(timer));
280+
readTimers.forEach((timer) => void clearTimeout(timer));
281+
};
276282
}, [messages]);
277283

278284
// Log assistant message part event - called when a new part becomes visible
@@ -349,9 +355,7 @@ export default function ChatPanel({ onNewMessage }: ChatPanelProps) {
349355
onNewMessage();
350356
}
351357
});
352-
353-
/* Removed internal notification state as requested */
354-
358+
355359
// Show notification when a new assistant message part appears
356360
useEffect(() => {
357361
if (messages.length === 0) return;
@@ -361,14 +365,6 @@ export default function ChatPanel({ onNewMessage }: ChatPanelProps) {
361365
}
362366
}, [messages, visibleMessagePartCount]);
363367

364-
// Cleanup any pending read timers on unmount
365-
useEffect(() => {
366-
return () => {
367-
deliveredTimersRef.current.forEach((timer) => clearTimeout(timer));
368-
readTimersRef.current.forEach((timer) => clearTimeout(timer));
369-
};
370-
}, []);
371-
372368
return (
373369
<div className="h-full flex flex-col overflow-hidden">
374370
<div className="flex items-center gap-2.5 bg-gray-50 border-b border-gray-300 px-3 py-2.5">

0 commit comments

Comments
 (0)