Skip to content

Commit 44b5877

Browse files
KyleAMathewsclaude
andauthored
Add framework overview page content (#842)
* docs: add framework overview pages for Vue, Solid, Svelte, and Angular Replace placeholder content with complete framework-specific documentation for all non-React adapters. Each overview includes: - Installation instructions - Basic usage with useLiveQuery (or injectLiveQuery for Angular) - Dependency arrays/reactive parameters documentation - Framework-specific code examples and best practices These pages follow the same structure as the React overview but are tailored to each framework's conventions and only document the useLiveQuery hook (the only hook currently available for these frameworks). * docs: fix reactivity patterns in Solid and Vue framework overviews Correct the documentation based on actual source code and test verification: **Solid changes:** - Remove incorrect dependency array pattern - Document automatic fine-grained reactivity tracking - Show correct signal usage inside query functions - Add examples of good vs bad patterns - Explain that Solid tracks signals automatically without deps **Vue changes:** - Fix dependency array to pass refs directly, not wrapped in functions - Show correct pattern: [minAge] instead of [() => minAge] - Add toRef pattern for props - Clarify getter functions are only needed for non-ref values - Add example of using pre-created collections with reactive refs Both frameworks now match their actual implementations as verified against packages/*-db/src/*.ts source files and test files. * docs: fix Angular and Svelte framework overview issues Address critical issues identified in external code review: **Angular fixes:** - Replace invalid destructuring syntax ({ data } = injectLiveQuery) with correct field assignment (query = injectLiveQuery) - Update all templates to call signals with () as per Angular API - Add separate examples for Angular 16+ (@input) vs 17+ (input.required) - Add note explaining all return values are Angular signals - Ensure all examples use query.data() and query.isLoading() **Svelte fixes:** - Remove incorrect $ prefix from all examples (not Svelte stores) - Change to const query = useLiveQuery() pattern - Update all templates to use query.data and query.isLoading directly - Add note explaining Svelte 5 runes return reactive values via getters - Ensure consistency: query.data (no call), query.isLoading (no call) These changes align documentation with actual adapter implementations and fix syntax errors that would cause compile failures. * docs: address second-round reviewer feedback on Angular and Solid Apply precision improvements from external code review: **Angular:** - Soften parameter-change behavior wording to avoid over-promising timing guarantees (changed from "isLoading becomes true" to "status()/isLoading() reflect the new query's lifecycle") - Add template syntax version note explaining @if/@for requires Angular 17+ (v16 users should use *ngIf/*ngFor) **Solid:** - Fix contradictory intro sentence that claimed "all return values should be called as functions" while the note correctly stated "data is a plain array" - Now states clearly: "data is a plain array and status fields are accessors" All changes align documentation with exact adapter behavior and prevent user confusion about API contracts. --------- Co-authored-by: Claude <[email protected]>
1 parent f66f2cf commit 44b5877

File tree

4 files changed

+760
-6
lines changed

4 files changed

+760
-6
lines changed

docs/framework/angular/overview.md

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,200 @@ npm install @tanstack/angular-db
1313

1414
See the [Angular Functions Reference](../reference/index.md) to see the full list of functions available in the Angular Adapter.
1515

16+
For comprehensive documentation on writing queries (filtering, joins, aggregations, etc.), see the [Live Queries Guide](../../guides/live-queries).
17+
1618
## Basic Usage
19+
20+
### injectLiveQuery
21+
22+
The `injectLiveQuery` function creates a live query that automatically updates your component when data changes. It returns an object containing Angular signals for reactive state management:
23+
24+
```typescript
25+
import { Component } from '@angular/core'
26+
import { injectLiveQuery } from '@tanstack/angular-db'
27+
import { eq } from '@tanstack/db'
28+
29+
@Component({
30+
selector: 'app-todo-list',
31+
standalone: true,
32+
template: `
33+
@if (query.isLoading()) {
34+
<div>Loading...</div>
35+
} @else {
36+
<ul>
37+
@for (todo of query.data(); track todo.id) {
38+
<li>{{ todo.text }}</li>
39+
}
40+
</ul>
41+
}
42+
`
43+
})
44+
export class TodoListComponent {
45+
query = injectLiveQuery((q) =>
46+
q.from({ todos: todosCollection })
47+
.where(({ todos }) => eq(todos.completed, false))
48+
.select(({ todos }) => ({ id: todos.id, text: todos.text }))
49+
)
50+
}
51+
```
52+
53+
**Note:** All return values (`data`, `isLoading`, `status`, etc.) are Angular signals, so call them with `()` in your template: `query.data()`, `query.isLoading()`.
54+
55+
> **Template Syntax:** Examples use Angular 17+ control flow (`@if`, `@for`). For Angular 16, use `*ngIf` and `*ngFor` instead.
56+
57+
### Reactive Parameters
58+
59+
For queries that depend on reactive values, use the `params` option to re-run the query when those values change:
60+
61+
```typescript
62+
import { Component, signal } from '@angular/core'
63+
import { injectLiveQuery } from '@tanstack/angular-db'
64+
import { gt } from '@tanstack/db'
65+
66+
@Component({
67+
selector: 'app-filtered-todos',
68+
standalone: true,
69+
template: `
70+
<div>{{ query.data().length }} high-priority todos</div>
71+
`
72+
})
73+
export class FilteredTodosComponent {
74+
minPriority = signal(5)
75+
76+
query = injectLiveQuery({
77+
params: () => ({ minPriority: this.minPriority() }),
78+
query: ({ params, q }) =>
79+
q.from({ todos: todosCollection })
80+
.where(({ todos }) => gt(todos.priority, params.minPriority))
81+
})
82+
}
83+
```
84+
85+
#### When to Use Reactive Parameters
86+
87+
Use the reactive `params` option when your query depends on:
88+
- Component signals
89+
- Input properties
90+
- Computed values
91+
- Other reactive state
92+
93+
When any reactive value accessed in the `params` function changes, the query is recreated and re-executed.
94+
95+
#### What Happens When Parameters Change
96+
97+
When a parameter value changes:
98+
1. The previous live-query collection is disposed
99+
2. A new query is created with the updated parameter values
100+
3. `status()`/`isLoading()` reflect the new query's lifecycle
101+
4. `data()` updates automatically when the new results arrive
102+
103+
#### Best Practices
104+
105+
**Use reactive params for dynamic queries:**
106+
107+
```typescript
108+
import { Component, Input, signal } from '@angular/core'
109+
import { injectLiveQuery } from '@tanstack/angular-db'
110+
import { eq, and } from '@tanstack/db'
111+
112+
@Component({
113+
selector: 'app-todo-list',
114+
standalone: true,
115+
template: `<div>{{ query.data().length }} todos</div>`
116+
})
117+
export class TodoListComponent {
118+
// Angular 16+ compatible input
119+
@Input({ required: true }) userId!: number
120+
status = signal('active')
121+
122+
// Good - reactive params track all dependencies
123+
query = injectLiveQuery({
124+
params: () => ({
125+
userId: this.userId,
126+
status: this.status()
127+
}),
128+
query: ({ params, q }) =>
129+
q.from({ todos: todosCollection })
130+
.where(({ todos }) => and(
131+
eq(todos.userId, params.userId),
132+
eq(todos.status, params.status)
133+
))
134+
})
135+
}
136+
```
137+
138+
**Using Angular 17+ signal inputs:**
139+
140+
```typescript
141+
import { Component, input, signal } from '@angular/core'
142+
import { injectLiveQuery } from '@tanstack/angular-db'
143+
import { eq, and } from '@tanstack/db'
144+
145+
@Component({
146+
selector: 'app-todo-list',
147+
standalone: true,
148+
template: `<div>{{ query.data().length }} todos</div>`
149+
})
150+
export class TodoListComponent {
151+
// Angular 17+ signal-based input
152+
userId = input.required<number>()
153+
status = signal('active')
154+
155+
query = injectLiveQuery({
156+
params: () => ({
157+
userId: this.userId(),
158+
status: this.status()
159+
}),
160+
query: ({ params, q }) =>
161+
q.from({ todos: todosCollection })
162+
.where(({ todos }) => and(
163+
eq(todos.userId, params.userId),
164+
eq(todos.status, params.status)
165+
))
166+
})
167+
}
168+
```
169+
170+
**Static queries don't need params:**
171+
172+
```typescript
173+
import { Component } from '@angular/core'
174+
import { injectLiveQuery } from '@tanstack/angular-db'
175+
176+
@Component({
177+
selector: 'app-all-todos',
178+
standalone: true,
179+
template: `<div>{{ query.data().length }} todos</div>`
180+
})
181+
export class AllTodosComponent {
182+
// No reactive dependencies - query never changes
183+
query = injectLiveQuery((q) =>
184+
q.from({ todos: todosCollection })
185+
)
186+
}
187+
```
188+
189+
**Access multiple signals in template:**
190+
191+
```typescript
192+
import { Component } from '@angular/core'
193+
import { injectLiveQuery } from '@tanstack/angular-db'
194+
import { eq } from '@tanstack/db'
195+
196+
@Component({
197+
selector: 'app-todos',
198+
standalone: true,
199+
template: `
200+
<div>Status: {{ query.status() }}</div>
201+
<div>Loading: {{ query.isLoading() }}</div>
202+
<div>Ready: {{ query.isReady() }}</div>
203+
<div>Total: {{ query.data().length }}</div>
204+
`
205+
})
206+
export class TodosComponent {
207+
query = injectLiveQuery((q) =>
208+
q.from({ todos: todosCollection })
209+
.where(({ todos }) => eq(todos.completed, false))
210+
)
211+
}
212+
```

docs/framework/solid/overview.md

Lines changed: 186 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,189 @@
11
---
22
title: TanStack DB Solid Adapter
3-
ref: docs/framework/react/adapter.md
4-
replace: { "React": "Solid", "react": "solid" }
3+
id: adapter
54
---
5+
6+
## Installation
7+
8+
```sh
9+
npm install @tanstack/solid-db
10+
```
11+
12+
## Solid Primitives
13+
14+
See the [Solid Functions Reference](../reference/index.md) to see the full list of primitives available in the Solid Adapter.
15+
16+
For comprehensive documentation on writing queries (filtering, joins, aggregations, etc.), see the [Live Queries Guide](../../guides/live-queries).
17+
18+
## Basic Usage
19+
20+
### useLiveQuery
21+
22+
The `useLiveQuery` primitive creates a live query that automatically updates your component when data changes. It returns an object where `data` is a plain array and status fields (e.g. `isLoading()`, `status()`) are accessors:
23+
24+
```tsx
25+
import { useLiveQuery } from '@tanstack/solid-db'
26+
import { eq } from '@tanstack/db'
27+
import { Show, For } from 'solid-js'
28+
29+
function TodoList() {
30+
const query = useLiveQuery((q) =>
31+
q.from({ todos: todosCollection })
32+
.where(({ todos }) => eq(todos.completed, false))
33+
.select(({ todos }) => ({ id: todos.id, text: todos.text }))
34+
)
35+
36+
return (
37+
<Show when={!query.isLoading()} fallback={<div>Loading...</div>}>
38+
<ul>
39+
<For each={query.data}>
40+
{(todo) => <li>{todo.text}</li>}
41+
</For>
42+
</ul>
43+
</Show>
44+
)
45+
}
46+
```
47+
48+
**Note:** `query.data` returns an array directly (not a function), but status fields like `isLoading()`, `status()`, etc. are accessor functions.
49+
50+
### Reactive Queries with Signals
51+
52+
Solid uses fine-grained reactivity, which means queries automatically track and respond to signal changes. Simply call signals inside your query function, and Solid will automatically recompute when they change:
53+
54+
```tsx
55+
import { createSignal } from 'solid-js'
56+
import { useLiveQuery } from '@tanstack/solid-db'
57+
import { gt } from '@tanstack/db'
58+
59+
function FilteredTodos(props: { minPriority: number }) {
60+
const query = useLiveQuery((q) =>
61+
q.from({ todos: todosCollection })
62+
.where(({ todos }) => gt(todos.priority, props.minPriority))
63+
)
64+
65+
return <div>{query.data.length} high-priority todos</div>
66+
}
67+
```
68+
69+
When `props.minPriority` changes, Solid's reactivity system automatically:
70+
1. Detects the prop access inside the query function
71+
2. Cleans up the previous live query collection
72+
3. Creates a new query with the updated value
73+
4. Updates the component with the new data
74+
75+
#### Using Signals from Component State
76+
77+
```tsx
78+
import { createSignal } from 'solid-js'
79+
import { useLiveQuery } from '@tanstack/solid-db'
80+
import { eq, and } from '@tanstack/db'
81+
82+
function TodoList() {
83+
const [userId, setUserId] = createSignal(1)
84+
const [status, setStatus] = createSignal('active')
85+
86+
// Solid automatically tracks userId() and status() calls
87+
const query = useLiveQuery((q) =>
88+
q.from({ todos: todosCollection })
89+
.where(({ todos }) => and(
90+
eq(todos.userId, userId()),
91+
eq(todos.status, status())
92+
))
93+
)
94+
95+
return (
96+
<div>
97+
<select onChange={(e) => setStatus(e.currentTarget.value)}>
98+
<option value="active">Active</option>
99+
<option value="completed">Completed</option>
100+
</select>
101+
<div>{query.data.length} todos</div>
102+
</div>
103+
)
104+
}
105+
```
106+
107+
**Key Point:** Unlike React, you don't need dependency arrays. Solid's reactive system automatically tracks any signals, props, or stores accessed during query execution.
108+
109+
#### Best Practices
110+
111+
**Access signals inside the query function:**
112+
113+
```tsx
114+
import { createSignal } from 'solid-js'
115+
import { useLiveQuery } from '@tanstack/solid-db'
116+
import { gt } from '@tanstack/db'
117+
118+
function TodoList() {
119+
const [minPriority, setMinPriority] = createSignal(5)
120+
121+
// Good - signal accessed inside query function
122+
const query = useLiveQuery((q) =>
123+
q.from({ todos: todosCollection })
124+
.where(({ todos }) => gt(todos.priority, minPriority()))
125+
)
126+
127+
// Solid automatically tracks minPriority() and recomputes when it changes
128+
return <div>{query.data.length} todos</div>
129+
}
130+
```
131+
132+
**Don't read signals outside the query function:**
133+
134+
```tsx
135+
import { createSignal } from 'solid-js'
136+
import { useLiveQuery } from '@tanstack/solid-db'
137+
import { gt } from '@tanstack/db'
138+
139+
function TodoList() {
140+
const [minPriority, setMinPriority] = createSignal(5)
141+
142+
// Bad - reading signal outside query function
143+
const currentPriority = minPriority()
144+
const query = useLiveQuery((q) =>
145+
q.from({ todos: todosCollection })
146+
.where(({ todos }) => gt(todos.priority, currentPriority))
147+
)
148+
// Won't update when minPriority changes!
149+
150+
return <div>{query.data.length} todos</div>
151+
}
152+
```
153+
154+
**Static queries need no special handling:**
155+
156+
```tsx
157+
import { useLiveQuery } from '@tanstack/solid-db'
158+
159+
function AllTodos() {
160+
// No signals accessed - query never changes
161+
const query = useLiveQuery((q) =>
162+
q.from({ todos: todosCollection })
163+
)
164+
165+
return <div>{query.data.length} todos</div>
166+
}
167+
```
168+
169+
### Using Pre-created Collections
170+
171+
You can also pass an existing collection to `useLiveQuery`. This is useful for sharing queries across components:
172+
173+
```tsx
174+
import { createLiveQueryCollection } from '@tanstack/db'
175+
import { useLiveQuery } from '@tanstack/solid-db'
176+
177+
// Create collection outside component
178+
const todosQuery = createLiveQueryCollection((q) =>
179+
q.from({ todos: todosCollection })
180+
.where(({ todos }) => eq(todos.active, true))
181+
)
182+
183+
function TodoList() {
184+
// Pass existing collection
185+
const query = useLiveQuery(() => todosQuery)
186+
187+
return <div>{query.data.length} todos</div>
188+
}
189+
```

0 commit comments

Comments
 (0)