Skip to content

Commit 4d67c1c

Browse files
authored
feat(core): streamedQuery (#8814)
* feat: streamedQuery * feat: streaming example * chore: move * chore: fix lock file * docs: streamedQuery
1 parent f03b109 commit 4d67c1c

File tree

19 files changed

+1297
-395
lines changed

19 files changed

+1297
-395
lines changed

docs/config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,10 @@
605605
"label": "QueriesObserver",
606606
"to": "reference/QueriesObserver"
607607
},
608+
{
609+
"label": "streamedQuery",
610+
"to": "reference/streamedQuery"
611+
},
608612
{
609613
"label": "focusManager",
610614
"to": "reference/focusManager"
@@ -957,6 +961,10 @@
957961
{
958962
"label": "Devtools Embedded Panel",
959963
"to": "framework/react/examples/devtools-panel"
964+
},
965+
{
966+
"label": "Chat example (streaming)",
967+
"to": "framework/react/examples/chat"
960968
}
961969
]
962970
},

docs/reference/QueryObserver.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ id: QueryObserver
33
title: QueryObserver
44
---
55

6-
## `QueryObserver`
7-
86
The `QueryObserver` can be used to observe and switch between queries.
97

108
```tsx

docs/reference/streamedQuery.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
id: streamedQuery
3+
title: streamedQuery
4+
---
5+
6+
`streamedQuery` is a helper function to create a query function that streams data from an [AsyncIterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncIterator). Data will be an Array of all the chunks received. The query will be in a `pending` state until the first chunk of data is received, but will go to `success` after that. The query will stay in fetchStatus `fetching` until the stream ends.
7+
8+
```tsx
9+
const query = queryOptions({
10+
queryKey: ['data'],
11+
queryFn: streamedQuery({
12+
queryFn: fetchDataInChunks,
13+
}),
14+
})
15+
```
16+
17+
**Options**
18+
19+
- `queryFn: (context: QueryFunctionContext) => Promise<AsyncIterable<TData>>`
20+
- **Required**
21+
- The function that returns a Promise of an AsyncIterable of data to stream in.
22+
- Receives a [QueryFunctionContext](../guides/query-functions.md#queryfunctioncontext)
23+
- `refetchMode?: 'append' | 'reset'`
24+
- optional
25+
- when set to `'reset'`, the query will erase all data and go back into `pending` state when a refetch occurs.
26+
- when set ot `'append'`, data will be appended on a refetch.
27+
- defaults to `'reset'`

examples/react/chat/.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["plugin:react/jsx-runtime", "plugin:react-hooks/recommended"]
3+
}

examples/react/chat/.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
pnpm-lock.yaml
15+
yarn.lock
16+
package-lock.json
17+
18+
# misc
19+
.DS_Store
20+
.env.local
21+
.env.development.local
22+
.env.test.local
23+
.env.production.local
24+
25+
npm-debug.log*
26+
yarn-debug.log*
27+
yarn-error.log*

examples/react/chat/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example
2+
3+
To run this example:
4+
5+
- `npm install`
6+
- `npm run dev`

examples/react/chat/index.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" type="image/svg+xml" href="/emblem-light.svg" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1" />
7+
<meta name="theme-color" content="#000000" />
8+
9+
<title>TanStack Query React Simple Example App</title>
10+
</head>
11+
<body>
12+
<noscript>You need to enable JavaScript to run this app.</noscript>
13+
<div id="root"></div>
14+
<script type="module" src="/src/index.tsx"></script>
15+
</body>
16+
</html>

examples/react/chat/package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "@tanstack/query-example-chat",
3+
"private": true,
4+
"type": "module",
5+
"scripts": {
6+
"dev": "vite",
7+
"build": "vite build",
8+
"preview": "vite preview"
9+
},
10+
"dependencies": {
11+
"@tanstack/react-query": "^5.68.0",
12+
"@tanstack/react-query-devtools": "^5.68.0",
13+
"react": "^19.0.0",
14+
"react-dom": "^19.0.0"
15+
},
16+
"devDependencies": {
17+
"@tailwindcss/vite": "^4.0.14",
18+
"@vitejs/plugin-react": "^4.3.3",
19+
"tailwindcss": "^4.0.14",
20+
"typescript": "5.8.2",
21+
"vite": "^5.3.5"
22+
}
23+
}
Lines changed: 13 additions & 0 deletions
Loading

examples/react/chat/src/chat.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import {
2+
queryOptions,
3+
experimental_streamedQuery as streamedQuery,
4+
} from '@tanstack/react-query'
5+
6+
const answers = [
7+
"I'm just an example chat, I can't really answer any questions :(".split(' '),
8+
'TanStack is great. Would you like to know more?'.split(' '),
9+
]
10+
11+
function chatAnswer(_question: string) {
12+
return {
13+
async *[Symbol.asyncIterator]() {
14+
const answer = answers[Math.floor(Math.random() * answers.length)]
15+
let index = 0
16+
while (index < answer.length) {
17+
await new Promise((resolve) =>
18+
setTimeout(resolve, 100 + Math.random() * 300),
19+
)
20+
yield answer[index++]
21+
}
22+
},
23+
}
24+
}
25+
26+
export const chatQueryOptions = (question: string) =>
27+
queryOptions({
28+
queryKey: ['chat', question],
29+
queryFn: streamedQuery({
30+
queryFn: () => chatAnswer(question),
31+
}),
32+
staleTime: Infinity,
33+
})

0 commit comments

Comments
 (0)