Skip to content

fix(react): keep chat stable with inline options - #1450

Merged
1egoman merged 2 commits into
livekit:mainfrom
fatihcvs:fix/chat-inline-options
Sep 23, 2026
Merged

1egoman merged 2 commits into
livekit:mainfrom
fatihcvs:fix/chat-inline-options

Conversation

@fatihcvs

Copy link
Copy Markdown
Contributor

Passing inline options such as useChat({ room }) recreates chat setup on every render. Resetting the message observable then updates state with a new empty array, triggering another render and setup. Equivalent options can therefore cause a render loop and discard message history.

Depend on the individual option values rather than the containing object, while retaining the existing room/disconnect reset behavior.

Validation:

  • Three hook regressions fail before the change (a bounded render guard prevents the test runner from hanging) and pass afterward. They cover inline default/custom-topic options, messages surviving a rerender, and history/subscriptions moving to a different room.
  • Tests use the real hook and SDK Room events in JSDOM, with no server connection or hook mocks.
  • 121 core/react/styles tests pass. pnpm build:react, React lint (warnings, no errors), pnpm format:check, and React API check pass.

Includes a React patch changeset. This is independent of #1449: it changes React option identity handling, not core per-topic registration. Developed and verified with OpenAI Codex assistance.

@changeset-bot

changeset-bot Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8e2d0c4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 6 packages
Name Type
@livekit/components-react Patch
@livekit/agents-ui Patch
@livekit/component-example-next Patch
@livekit/components-js-docs Patch
@livekit/component-docs-storybook Patch
@livekit/components-docs-gen Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Sep 19, 2026

Copy link
Copy Markdown

@fatihcvs is attempting to deploy a commit to the LiveKit Team on Vercel.

A member of the Team first needs to authorize it.

@1egoman 1egoman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good to me! One small suggestion to make some docstring comment updates.

Comment on lines 42 to +44
export function useChat(options?: ChatOptions & { room?: Room }) {
const room = useEnsureRoom(options?.room);
const { channelTopic, updateChannelTopic, messageEncoder, messageDecoder } = options ?? {};

@1egoman 1egoman Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both messageEncoder and messageDecoder here are functions. It's probably fairly likely somebody would think they could do something like this:

useChat({
  room,
  messageDecoder: (payload) => JSON.parse(new TextDecoder().decode(payload)),
});

If they did, then they run into the same issue where there needs to be memoization done to the function with useCallback.

Given both of these are deprecated, I think it's probably fine to just add a docstring comment on each in ChatOptions which calls out that they need to be memoized. Would you be able to do this?

(The other option which I think could work would be something like on every render, storing messageEncoder and messageDecoder into refs, and then using these refs imperatively everywhere instead of the prop values. However, this is a lot of extra infrastructure to add and since the params are deprecated I think it makes more sense to keep things stable and not change behavior for existing downstream users.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the note to both ChatOptions callbacks in 8e2d0c4: memoize with useCallback or define them outside the component, with an explanation of the history reset/render-loop risk. Kept the existing behavior as suggested. Prettier and git diff --check pass.

@1egoman 1egoman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

@1egoman
1egoman merged commit 6be1b95 into livekit:main Sep 23, 2026
3 of 4 checks passed
@github-actions github-actions Bot mentioned this pull request Sep 23, 2026
@fatihcvs

Copy link
Copy Markdown
Contributor Author

You're welcome! Thanks for the review and the suggestion.

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.

2 participants