Files
upstream-tanstack-query/docs/framework/lit/guides/parallel-queries.md
upstream-mirror 3a013ccdfe
Some checks failed
autofix.ci / autofix (push) Failing after 4s
Release / Release (push) Has been skipped
GitHub Actions Security Analysis / Run zizmor (push) Failing after 2s
snapshot of https://github.com/TanStack/query.git (main, 2026-09-16; blobs > 131072B omitted)
2026-09-16 01:13:08 +05:00

135 lines
3.7 KiB
Markdown

---
id: parallel-queries
title: Parallel Queries
---
Parallel queries are queries that run at the same time so the UI does not wait for one request before starting the next.
## Manual Parallel Queries
When the number of queries is fixed, create multiple query controllers on the same host. They will all subscribe when the host connects.
```ts
import { LitElement, html } from 'lit'
import { createQueryController } from '@tanstack/lit-query'
class DashboardView extends LitElement {
private readonly users = createQueryController(this, {
queryKey: ['users'],
queryFn: fetchUsers,
})
private readonly teams = createQueryController(this, {
queryKey: ['teams'],
queryFn: fetchTeams,
})
private readonly projects = createQueryController(this, {
queryKey: ['projects'],
queryFn: fetchProjects,
})
render() {
const users = this.users()
const teams = this.teams()
const projects = this.projects()
if (users.isPending || teams.isPending || projects.isPending) {
return html`Loading...`
}
if (users.isError || teams.isError || projects.isError) {
return html`Unable to load dashboard`
}
return html`
<dashboard-summary
.users=${users.data}
.teams=${teams.data}
.projects=${projects.data}
></dashboard-summary>
`
}
}
```
Each controller receives the same `ReactiveControllerHost`. If no explicit `QueryClient` is passed, each controller resolves the nearest connected `QueryClientProvider`.
## Dynamic Parallel Queries
When the number of queries changes with host state, use [`createQueriesController`](../reference/functions/createQueriesController.md). It accepts a `queries` array and returns an accessor for the array of query results.
Use an options getter when the query list depends on reactive host fields:
```ts
import { LitElement, html } from 'lit'
import { createQueriesController } from '@tanstack/lit-query'
class UsersDetails extends LitElement {
static properties = {
userIds: { attribute: false },
}
userIds: Array<string> = []
private readonly users = createQueriesController(this, () => ({
queries: this.userIds.map((id) => ({
queryKey: ['user', id],
queryFn: () => fetchUserById(id),
})),
}))
render() {
const userQueries = this.users()
return html`
<ul>
${userQueries.map((query, index) => {
if (query.isPending) return html`<li>Loading...</li>`
if (query.isError) return html`<li>Error loading user</li>`
return html`<li>${this.userIds[index]}: ${query.data.name}</li>`
})}
</ul>
`
}
}
```
The order of the results matches the order of the input queries.
## Combining Results
Use `combine` when a component wants one derived value instead of an array of query results:
```ts
private readonly dashboard = createQueriesController(this, {
queries: [
{ queryKey: ['stats'], queryFn: fetchStats },
{ queryKey: ['projects'], queryFn: fetchProjects },
],
combine: ([stats, projects]) => ({
activeUsers: stats.data?.activeUsers ?? 0,
projects: projects.data ?? [],
isPending: stats.isPending || projects.isPending,
isError: stats.isError || projects.isError,
}),
})
```
```ts
render() {
const dashboard = this.dashboard()
if (dashboard.isPending) return html`Loading...`
if (dashboard.isError) return html`Unable to load dashboard`
return html`
<p>Total projects: ${dashboard.projects.length}</p>
<p>Active users: ${dashboard.activeUsers}</p>
`
}
```
Having the same query key more than once in the `queries` array can cause those entries to share cached data. Deduplicate repeated keys first if each rendered row needs independent query state.