File: chat.md | Updated: 11/15/2025
Search...
+ K
Auto
Docs Examples GitHub Contributors
Docs Examples GitHub Contributors
Docs Examples GitHub Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Docs Examples Github Contributors
Maintainers Partners Support Learn StatsBETA Discord Merch Blog GitHub Ethos Brand Guide
Documentation
Framework
React
Version
Latest
Search...
+ K
Menu
Getting Started
Guides & Concepts
API Reference
ESLint
Examples
Plugins
Framework
React
Version
Latest
Menu
Getting Started
Guides & Concepts
API Reference
ESLint
Examples
Plugins
React Example: Chat
=========================================================================================================================================================================================================================================================================================================================================================================================
Code ExplorerCode
Interactive SandboxSandbox
public
src
chat.ts
index.tsx
message.tsx
style.css
.eslintrc
.gitignore
README.md
index.html
package.json
tsconfig.json
vite.config.ts
tsx
import ReactDOM from 'react-dom/client'
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import './style.css'
import { useState } from 'react'
import { chatQueryOptions } from './chat'
import { Message } from './message'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<Example />
</QueryClientProvider>
)
}
function ChatMessage({ question }: { question: string }) {
const { error, data = [], isFetching } = useQuery(chatQueryOptions(question))
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<Message message={{ content: question, isQuestion: true }} />
<Message
inProgress={isFetching}
message={{ content: data.join(' '), isQuestion: false }}
/>
</div>
)
}
function Example() {
const [questions, setQuestions] = useState<Array<string>>([])
const [currentQuestion, setCurrentQuestion] = useState('')
const submitMessage = () => {
setQuestions([...questions, currentQuestion])
setCurrentQuestion('')
}
return (
<div className="flex flex-col h-screen max-w-3xl mx-auto p-4">
<h1 className="text-3xl font-bold text-gray-800">
TanStack Chat Example
</h1>
<div className="overflow-y-auto mb-4 space-y-4">
{questions.map((question) => (
<ChatMessage key={question} question={question} />
))}
</div>
<div className="flex items-center space-x-2">
<input
className="flex-1 p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-100"
value={currentQuestion}
onChange={(e) => setCurrentQuestion(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
submitMessage()
}
}}
placeholder="Type your message..."
/>
<button
onClick={submitMessage}
disabled={!currentQuestion.trim()}
className="flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-4 py-2 rounded-2xl shadow-md transition"
>
<span>Send</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z" />
<path d="m21.854 2.147-10.94 10.939" />
</svg>
</button>
</div>
</div>
)
}
const rootElement = document.getElementById('root') as HTMLElement
ReactDOM.createRoot(rootElement).render(<App />)
import ReactDOM from 'react-dom/client'
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import './style.css'
import { useState } from 'react'
import { chatQueryOptions } from './chat'
import { Message } from './message'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<Example />
</QueryClientProvider>
)
}
function ChatMessage({ question }: { question: string }) {
const { error, data = [], isFetching } = useQuery(chatQueryOptions(question))
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<Message message={{ content: question, isQuestion: true }} />
<Message
inProgress={isFetching}
message={{ content: data.join(' '), isQuestion: false }}
/>
</div>
)
}
function Example() {
const [questions, setQuestions] = useState<Array<string>>([])
const [currentQuestion, setCurrentQuestion] = useState('')
const submitMessage = () => {
setQuestions([...questions, currentQuestion])
setCurrentQuestion('')
}
return (
<div className="flex flex-col h-screen max-w-3xl mx-auto p-4">
<h1 className="text-3xl font-bold text-gray-800">
TanStack Chat Example
</h1>
<div className="overflow-y-auto mb-4 space-y-4">
{questions.map((question) => (
<ChatMessage key={question} question={question} />
))}
</div>
<div className="flex items-center space-x-2">
<input
className="flex-1 p-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-gray-100"
value={currentQuestion}
onChange={(e) => setCurrentQuestion(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
submitMessage()
}
}}
placeholder="Type your message..."
/>
<button
onClick={submitMessage}
disabled={!currentQuestion.trim()}
className="flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white font-semibold px-4 py-2 rounded-2xl shadow-md transition"
>
<span>Send</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z" />
<path d="m21.854 2.147-10.94 10.939" />
</svg>
</button>
</div>
</div>
)
}
const rootElement = document.getElementById('root') as HTMLElement
ReactDOM.createRoot(rootElement).render(<App />)
[###### Want to Skip the Docs?
Query.gg - The Official React Query Course
\
“If you’re serious about *really* understanding React Query, there’s no better way than with query.gg”—Tanner Linsley
Learn More](https://query.gg/?s=tanstack)
