Skip to content

Commit 60cbd75

Browse files
authored
docs(angular-query): add guides (#6530)
* docs(angular-query): add guides * docs(angular-query): add mutations guide * docs(angular-query): guides improvements * docs(angular-query): update docs * docs(angular-query): add initial query data guide * add keywords and optimistic updates guide * Replace React specifics with Angular ones
1 parent 84e2ef2 commit 60cbd75

31 files changed

+1890
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
id: background-fetching-indicators
3+
title: Background Fetching Indicators
4+
ref: docs/react/guides/background-fetching-indicators.md
5+
---
6+
7+
[//]: # 'Example'
8+
9+
```ts
10+
@Component({
11+
selector: 'posts',
12+
template: `
13+
@switch (query.status()) {
14+
@case ('pending') {
15+
Loading...
16+
}
17+
@case ('error') {
18+
An error has occurred: {{ query.error()?.message }}
19+
}
20+
@default {
21+
@if (query.isFetching()) {
22+
Refreshing...
23+
}
24+
@for (todo of query.data()) {
25+
<todo [todo]="todo" />
26+
}
27+
}
28+
}
29+
`,
30+
})
31+
export class TodosComponent {
32+
todosQuery = injectQuery(() => ({
33+
queryKey: ['todos'],
34+
queryFn: fetchTodos,
35+
}))
36+
}
37+
```
38+
39+
[//]: # 'Example'
40+
[//]: # 'Example2'
41+
42+
```ts
43+
import { injectIsFetching } from '@tanstack/angular-query-experimental'
44+
45+
@Component({
46+
selector: 'global-loading-indicator',
47+
template: `
48+
@if (isFetching()) {
49+
<div>Queries are fetching in the background...</div>
50+
}
51+
`,
52+
})
53+
export class GlobalLoadingIndicatorComponent {
54+
isFetching = injectIsFetching()
55+
}
56+
```
57+
58+
[//]: # 'Example2'

docs/angular/guides/caching.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
id: caching
3+
title: Caching Examples
4+
---
5+
6+
> Please thoroughly read the [Important Defaults](../guides/important-defaults) before reading this guide
7+
8+
## Basic Example
9+
10+
This caching example illustrates the story and lifecycle of:
11+
12+
- Query Instances with and without cache data
13+
- Background Refetching
14+
- Inactive Queries
15+
- Garbage Collection
16+
17+
Let's assume we are using the default `gcTime` of **5 minutes** and the default `staleTime` of `0`.
18+
19+
- A new instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` initializes.
20+
- Since no other queries have been made with the `['todos']` query key, this query will show a hard loading state and make a network request to fetch the data.
21+
- When the network request has completed, the returned data will be cached under the `['todos']` key.
22+
- The date will be marked as stale after the configured `staleTime` (defaults to `0`, or immediately).
23+
- A second instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` initializes elsewhere.
24+
- Since the cache already has data for the `['todos']` key from the first query, that data is immediately returned from the cache.
25+
- The new instance triggers a new network request using its query function.
26+
- Note that regardless of whether both `fetchTodos` query functions are identical or not, both queries' [`status`](../reference/injectQuery) are updated (including `isFetching`, `isPending`, and other related values) because they have the same query key.
27+
- When the request completes successfully, the cache's data under the `['todos']` key is updated with the new data, and both instances are updated with the new data.
28+
- Both instances of the `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` query are destroyed and no longer in use.
29+
- Since there are no more active instances of this query, a garbage collection timeout is set using `gcTime` to delete and garbage collect the query (defaults to **5 minutes**).
30+
- Before the cache timeout has completed, another instance of `injectQuery(() => ({ queryKey: ['todos'], queyFn: fetchTodos })` mounts. The query immediately returns the available cached data while the `fetchTodos` function is being run in the background. When it completes successfully, it will populate the cache with fresh data.
31+
- The final instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` gets destroyed.
32+
- No more instances of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` appear within **5 minutes**.
33+
- The cached data under the `['todos']` key is deleted and garbage collected.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
id: default-query-function
3+
title: Default Query Function
4+
ref: docs/react/guides/default-query-function.md
5+
---
6+
7+
[//]: # 'Example'
8+
9+
```ts
10+
// Define a default query function that will receive the query key
11+
const defaultQueryFn: QueryFunction = async ({ queryKey }) => {
12+
const { data } = await axios.get(
13+
`https://jsonplaceholder.typicode.com${queryKey[0]}`,
14+
)
15+
return data
16+
}
17+
18+
// provide the default query function to your app with defaultOptions
19+
const queryClient = new QueryClient({
20+
defaultOptions: {
21+
queries: {
22+
queryFn: defaultQueryFn,
23+
},
24+
},
25+
})
26+
27+
bootstrapApplication(MyAppComponent, {
28+
providers: [provideAngularQuery(queryClient)],
29+
})
30+
31+
export class PostsComponent {
32+
// All you have to do now is pass a key!
33+
postsQuery = injectQuery<Array<Post>>(() => ({
34+
queryKey: ['/posts'],
35+
}))
36+
// ...
37+
}
38+
39+
export class PostComponent {
40+
// You can even leave out the queryFn and just go straight into options
41+
postQuery = injectQuery<Post>(() => ({
42+
enabled: this.postIdSignal() > 0,
43+
queryKey: [`/posts/${this.postIdSignal()}`],
44+
}))
45+
// ...
46+
}
47+
```
48+
49+
[//]: # 'Example'
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
id: dependent-queries
3+
title: Dependent Queries
4+
ref: docs/react/guides/dependent-queries.md
5+
replace: { 'useQuery': 'injectQuery', 'useQueries': 'injectQueries' }
6+
---
7+
8+
[//]: # 'Example'
9+
10+
```ts
11+
// Get the user
12+
userQuery = injectQuery(() => ({
13+
queryKey: ['user', email],
14+
queryFn: getUserByEmail,
15+
}))
16+
17+
// Then get the user's projects
18+
projectsQuery = injectQuery(() => ({
19+
queryKey: ['projects', this.userQuery.data()?.id],
20+
queryFn: getProjectsByUser,
21+
// The query will not execute until the user id exists
22+
enabled: !!this.userQuery.data()?.id,
23+
}))
24+
```
25+
26+
[//]: # 'Example'
27+
[//]: # 'Example2'
28+
29+
```ts
30+
// injectQueries is under development for Angular Query
31+
```
32+
33+
[//]: # 'Example2'
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
id: disabling-queries
3+
title: Disabling/Pausing Queries
4+
ref: docs/react/guides/disabling-queries.md
5+
replace: { 'useQuery': 'injectQuery' }
6+
---
7+
8+
[//]: # 'Example'
9+
10+
```ts
11+
@Component({
12+
selector: 'todos',
13+
template: `<div>
14+
<button (click)="query.refetch()">Fetch Todos</button>
15+
16+
@if (query.data()) {
17+
<ul>
18+
@for (todo of query.data(); track todo.id) {
19+
<li>{{ todo.title }}</li>
20+
}
21+
</ul>
22+
} @else {
23+
@if (query.isError()) {
24+
<span>Error: {{ query.error().message }}</span>
25+
} @else if (query.isLoading()) {
26+
<span>Loading...</span>
27+
} @else if (!query.isLoading() && !query.isError()) {
28+
<span>Not ready ...</span>
29+
}
30+
}
31+
32+
<div>{{ query.isLoading() ? 'Fetching...' : '' }}</div>
33+
</div>`,
34+
})
35+
export class TodosComponent {
36+
query = injectQuery(() => ({
37+
queryKey: ['todos'],
38+
queryFn: fetchTodoList,
39+
enabled: false,
40+
}))
41+
}
42+
```
43+
44+
[//]: # 'Example'
45+
[//]: # 'Example2'
46+
47+
```ts
48+
@Component({
49+
selector: 'todos',
50+
template: `
51+
<div>
52+
// 🚀 applying the filter will enable and execute the query
53+
<filters-form onApply="filter.set" />
54+
<todos-table data="query.data()" />
55+
</div>
56+
`,
57+
})
58+
export class TodosComponent {
59+
filter = signal('')
60+
61+
todosQuery = injectQuery(() => ({
62+
queryKey: ['todos', this.filter()],
63+
queryFn: () => fetchTodos(this.filter()),
64+
enabled: !!this.filter(),
65+
}))
66+
}
67+
```
68+
69+
[//]: # 'Example2'
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
id: does-this-replace-client-state
3+
title: Does TanStack Query replace global state managers?
4+
ref: docs/react/guides/does-this-replace-client-state.md
5+
replace:
6+
{
7+
'useQuery': 'injectQuery',
8+
'useMutation': 'injectMutation',
9+
'hook': 'function',
10+
}
11+
---

docs/angular/guides/filters.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
id: filters
3+
title: Filters
4+
ref: docs/react/guides/filters.md
5+
---
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
id: important-defaults
3+
title: Important Defaults
4+
ref: docs/react/guides/important-defaults.md
5+
replace:
6+
{
7+
'React': 'Angular',
8+
'react-query': 'angular-query',
9+
'useQuery': 'injectQuery',
10+
'useInfiniteQuery': 'injectInfiniteQuery',
11+
'useMemo and useCallback': 'setting signal values',
12+
}
13+
---
14+
15+
[//]: # 'Materials'
16+
[//]: # 'Materials'

0 commit comments

Comments
 (0)