diff --git a/.changeset/popular-roses-breathe.md b/.changeset/popular-roses-breathe.md new file mode 100644 index 000000000..69f64af69 --- /dev/null +++ b/.changeset/popular-roses-breathe.md @@ -0,0 +1,6 @@ +--- +"@livekit/components-core": patch +"@livekit/components-react": minor +--- + +Reset useChat messages when room disconnects diff --git a/packages/core/src/components/chat.ts b/packages/core/src/components/chat.ts index 0f91ae897..088b6e932 100644 --- a/packages/core/src/components/chat.ts +++ b/packages/core/src/components/chat.ts @@ -150,7 +150,7 @@ export function setupChat(room: Room, options?: ChatOptions) { function destroy() { onDestroyObservable.next(); onDestroyObservable.complete(); - topicSubjectMap.clear(); + topicSubjectMap.delete(room); } room.once(RoomEvent.Disconnected, destroy); diff --git a/packages/react/etc/components-react.api.md b/packages/react/etc/components-react.api.md index 1dfb63afd..03a716172 100644 --- a/packages/react/etc/components-react.api.md +++ b/packages/react/etc/components-react.api.md @@ -659,8 +659,8 @@ export function useAudioPlayback(room?: Room): { // @public export function useChat(options?: ChatOptions): { - send: ((message: string) => Promise) | undefined; - update: ((message: string, messageId: string) => Promise) | undefined; + send: (message: string) => Promise; + update: (message: string, messageId: string) => Promise; chatMessages: ReceivedChatMessage[]; isSending: boolean; }; diff --git a/packages/react/src/hooks/internal/useObservableState.ts b/packages/react/src/hooks/internal/useObservableState.ts index 9b892f11d..e81da9572 100644 --- a/packages/react/src/hooks/internal/useObservableState.ts +++ b/packages/react/src/hooks/internal/useObservableState.ts @@ -5,13 +5,20 @@ import type { Observable } from 'rxjs'; /** * @internal */ -export function useObservableState(observable: Observable | undefined, startWith: T) { +export function useObservableState( + observable: Observable | undefined, + startWith: T, + resetWhenObservableChanges = true, +) { const [state, setState] = React.useState(startWith); React.useEffect(() => { + if (resetWhenObservableChanges) { + setState(startWith); + } // observable state doesn't run in SSR if (typeof window === 'undefined' || !observable) return; const subscription = observable.subscribe(setState); return () => subscription.unsubscribe(); - }, [observable]); + }, [observable, resetWhenObservableChanges]); return state; } diff --git a/packages/react/src/hooks/useChat.ts b/packages/react/src/hooks/useChat.ts index 2c0d34a94..52f251ad8 100644 --- a/packages/react/src/hooks/useChat.ts +++ b/packages/react/src/hooks/useChat.ts @@ -1,8 +1,10 @@ +import * as React from 'react'; import type { ChatOptions, ReceivedChatMessage } from '@livekit/components-core'; import { setupChat } from '@livekit/components-core'; -import * as React from 'react'; +import { ConnectionState } from 'livekit-client'; import { useRoomContext } from '../context'; import { useObservableState } from './internal/useObservableState'; +import { useConnectionState } from './useConnectionStatus'; /** * The `useChat` hook provides chat functionality for a LiveKit room. @@ -14,14 +16,17 @@ import { useObservableState } from './internal/useObservableState'; */ export function useChat(options?: ChatOptions) { const room = useRoomContext(); - const [setup, setSetup] = React.useState>(); - const isSending = useObservableState(setup?.isSendingObservable, false); - const chatMessages = useObservableState(setup?.messageObservable, []); - - React.useEffect(() => { - const setupChatReturn = setupChat(room, options); - setSetup(setupChatReturn); - }, [room, options]); + const connectionState = useConnectionState(room); + const isDisconnected = React.useMemo( + () => connectionState === ConnectionState.Disconnected, + [connectionState], + ); // used to reset the messages on room disconnect + const setup = React.useMemo>( + () => setupChat(room, options), + [room, options, isDisconnected], + ); + const isSending = useObservableState(setup.isSendingObservable, false); + const chatMessages = useObservableState(setup.messageObservable, []); - return { send: setup?.send, update: setup?.update, chatMessages, isSending }; + return { send: setup.send, update: setup.update, chatMessages, isSending }; }