Skip to content

fix(web): stop chat composer lag on long chats#196

Open
alex-fedotyev wants to merge 1 commit into
ClickHouse:mainfrom
alex-fedotyev:alex/fix-chat-input-latency
Open

fix(web): stop chat composer lag on long chats#196
alex-fedotyev wants to merge 1 commit into
ClickHouse:mainfrom
alex-fedotyev:alex/fix-chat-input-latency

Conversation

@alex-fedotyev

Copy link
Copy Markdown
Contributor

Summary

Typing in the chat composer lags badly on long chats: dozens of keystrokes surface seconds later. This fixes it with two small, localized changes.

Root cause

The draft-persistence feature writes the composer draft into the global store on every keystroke (setDraft in ChatInput). ChatPage subscribes to the whole store with a no-selector useChatStore(), and MessageList is not memoized, so every keystroke re-renders the entire message list. On a short chat it is invisible; on a long one each render is expensive enough that input visibly stalls.

Fix

  • Memoize MessageList. Its props (messages, streamingBlocks, isStreaming) are stable store slices that do not change while typing, so the list no longer re-renders when unrelated state (the draft) updates.
  • Debounce the per-keystroke setDraft (400ms), flushed on blur and on send, and cancelled on send. The local textarea state still updates instantly, so the composer stays responsive; drafts still persist across session switches.

Test plan

  • npm run build passes (tsc + vite).
  • Verified locally: typing in a long chat is responsive again; the draft is restored when switching away and back; sending clears it.

Performance only, no visual change.

[ui-check: allow]

Typing in the composer stalled on long chats: dozens of keystrokes
would surface seconds later. Two things compounded:

- Every keystroke wrote the draft into the global store (setDraft), and
  ChatPage subscribes to the whole store, so each character re-rendered
  ChatPage.
- MessageList was not memoized, so it re-rendered the entire message
  list on every ChatPage render.

Memoize MessageList (all its props are stable store slices, unchanged
while typing) and debounce the draft write (400ms, flushed on blur and
on send). The composer stays responsive and drafts still persist across
session switches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant