diff --git a/.changeset/use-chat-nullish-id.md b/.changeset/use-chat-nullish-id.md new file mode 100644 index 000000000000..ca361e14f158 --- /dev/null +++ b/.changeset/use-chat-nullish-id.md @@ -0,0 +1,5 @@ +--- +"@ai-sdk/react": patch +--- + +Treat nullish `useChat` IDs the same as omitted IDs so the chat instance is not recreated on every render. diff --git a/packages/react/src/use-chat.ts b/packages/react/src/use-chat.ts index 819d77ba51cc..71df9a02830d 100644 --- a/packages/react/src/use-chat.ts +++ b/packages/react/src/use-chat.ts @@ -60,7 +60,9 @@ export function useChat({ const shouldRecreateChat = ('chat' in options && options.chat !== chatRef.current) || - ('id' in options && chatRef.current.id !== options.id); + ('id' in options && + options.id != null && + chatRef.current.id !== options.id); if (shouldRecreateChat) { chatRef.current = 'chat' in options ? options.chat : new Chat(options); diff --git a/packages/react/src/use-chat.ui.test.tsx b/packages/react/src/use-chat.ui.test.tsx index 84f0775923f7..a1619fd3ffc1 100644 --- a/packages/react/src/use-chat.ui.test.tsx +++ b/packages/react/src/use-chat.ui.test.tsx @@ -2216,6 +2216,82 @@ describe('id changes', () => { }); }); +describe('undefined id', () => { + setupTestComponent( + () => { + const [renderCount, setRenderCount] = React.useState(0); + const { + messages, + setMessages, + id: idKey, + } = useChat({ + id: undefined, + generateId: mockId(), + }); + + return ( +
+
{idKey}
+
{renderCount}
+
{JSON.stringify(messages, null, 2)}
+
+ ); + }, + { + init: TestComponent => , + }, + ); + + it('should not recreate chat when id is explicitly undefined', async () => { + const initialId = screen.getByTestId('id').textContent; + + await userEvent.click(screen.getByTestId('set-message')); + + await waitFor(() => { + expect( + JSON.parse(screen.getByTestId('messages').textContent ?? ''), + ).toStrictEqual([ + { + id: 'message-0', + role: 'user', + parts: [{ text: 'hi', type: 'text' }], + }, + ]); + }); + + await userEvent.click(screen.getByTestId('rerender')); + + expect(screen.getByTestId('id').textContent).toBe(initialId); + expect( + JSON.parse(screen.getByTestId('messages').textContent ?? ''), + ).toStrictEqual([ + { + id: 'message-0', + role: 'user', + parts: [{ text: 'hi', type: 'text' }], + }, + ]); + }); +}); + describe('chat instance changes', () => { setupTestComponent( () => {