From 18411402f5a21385a19c54dff5ac9f150cd5614d Mon Sep 17 00:00:00 2001 From: Avraham Sakal Date: Tue, 26 Aug 2025 19:01:39 -0400 Subject: [PATCH] example of SSE streaming --- layouts/LayoutDefault.tsx | 20 ++++++++++++++++---- pages/chat/+Page.tsx | 25 +++++++++++++++++-------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/layouts/LayoutDefault.tsx b/layouts/LayoutDefault.tsx index f10db97..da75de4 100644 --- a/layouts/LayoutDefault.tsx +++ b/layouts/LayoutDefault.tsx @@ -32,7 +32,12 @@ import { useMutation, useQuery, } from "@tanstack/react-query"; -import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import { + createTRPCClient, + httpBatchLink, + httpSubscriptionLink, + splitLink, +} from "@trpc/client"; import type { AppRouter } from "../trpc/router.js"; function makeQueryClient() { @@ -74,9 +79,16 @@ export default function LayoutDefault({ const [trpc] = useState(() => createTRPCClient({ links: [ - httpBatchLink({ - url: "/api/trpc", - methodOverride: "POST", + splitLink({ + // uses the httpSubscriptionLink for subscriptions + condition: (op) => op.type === "subscription", + true: httpSubscriptionLink({ + url: "/api/trpc", + }), + false: httpBatchLink({ + url: "/api/trpc", + methodOverride: "POST", + }), }), ], }) diff --git a/pages/chat/+Page.tsx b/pages/chat/+Page.tsx index 6a3f756..6e72308 100644 --- a/pages/chat/+Page.tsx +++ b/pages/chat/+Page.tsx @@ -1,25 +1,33 @@ import { Card, Textarea } from "@mantine/core"; import { useState } from "react"; -import { useTRPC } from "../../trpc/client"; +import { useTRPCClient } from "../../trpc/client"; export default function ChatPage() { const [inputMessage, setInputMessage] = useState(""); const [loading, setLoading] = useState(false); const [outputMessage, setOutputMessage] = useState(""); - const trpc = useTRPC(); + const trpc = useTRPCClient(); async function handleSendMessage() { setLoading(true); - const response = await trpc.chat.streamMessage.subscribe( + + const subscription = trpc.chat.streamMessage.subscribe( { message: inputMessage, }, - {} + { + onData(value) { + setOutputMessage((prevOutputMessage) => prevOutputMessage + value); + }, + onError(error) { + console.error(error); + }, + onComplete() { + subscription.unsubscribe(); + setLoading(false); + }, + } ); - for await (const chunk of response) { - setOutputMessage(chunk); - } - setLoading(false); } return (
@@ -33,6 +41,7 @@ export default function ChatPage() { onKeyDown={async (e) => { if (e.key === "Enter") { e.preventDefault(); + handleSendMessage(); } }} />