Skip to content

Commit

Permalink
docs(angular-query): add guides (#6530)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
arnoud-dv committed Dec 16, 2023
1 parent 84e2ef2 commit 60cbd75
Show file tree
Hide file tree
Showing 31 changed files with 1,890 additions and 0 deletions.
58 changes: 58 additions & 0 deletions docs/angular/guides/background-fetching-indicators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
id: background-fetching-indicators
title: Background Fetching Indicators
ref: docs/react/guides/background-fetching-indicators.md
---

[//]: # 'Example'

```ts
@Component({
selector: 'posts',
template: `
@switch (query.status()) {
@case ('pending') {
Loading...
}
@case ('error') {
An error has occurred: {{ query.error()?.message }}
}
@default {
@if (query.isFetching()) {
Refreshing...
}
@for (todo of query.data()) {
<todo [todo]="todo" />
}
}
}
`,
})
export class TodosComponent {
todosQuery = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodos,
}))
}
```

[//]: # 'Example'
[//]: # 'Example2'

```ts
import { injectIsFetching } from '@tanstack/angular-query-experimental'

@Component({
selector: 'global-loading-indicator',
template: `
@if (isFetching()) {
<div>Queries are fetching in the background...</div>
}
`,
})
export class GlobalLoadingIndicatorComponent {
isFetching = injectIsFetching()
}
```

[//]: # 'Example2'
33 changes: 33 additions & 0 deletions docs/angular/guides/caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
id: caching
title: Caching Examples
---

> Please thoroughly read the [Important Defaults](../guides/important-defaults) before reading this guide
## Basic Example

This caching example illustrates the story and lifecycle of:

- Query Instances with and without cache data
- Background Refetching
- Inactive Queries
- Garbage Collection

Let's assume we are using the default `gcTime` of **5 minutes** and the default `staleTime` of `0`.

- A new instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos }))` initializes.
- 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.
- When the network request has completed, the returned data will be cached under the `['todos']` key.
- The date will be marked as stale after the configured `staleTime` (defaults to `0`, or immediately).
- A second instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` initializes elsewhere.
- Since the cache already has data for the `['todos']` key from the first query, that data is immediately returned from the cache.
- The new instance triggers a new network request using its query function.
- 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.
- 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.
- Both instances of the `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` query are destroyed and no longer in use.
- 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**).
- 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.
- The final instance of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` gets destroyed.
- No more instances of `injectQuery(() => ({ queryKey: ['todos'], queryFn: fetchTodos })` appear within **5 minutes**.
- The cached data under the `['todos']` key is deleted and garbage collected.
49 changes: 49 additions & 0 deletions docs/angular/guides/default-query-function.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
id: default-query-function
title: Default Query Function
ref: docs/react/guides/default-query-function.md
---

[//]: # 'Example'

```ts
// Define a default query function that will receive the query key
const defaultQueryFn: QueryFunction = async ({ queryKey }) => {
const { data } = await axios.get(
`https://jsonplaceholder.typicode.com${queryKey[0]}`,
)
return data
}

// provide the default query function to your app with defaultOptions
const queryClient = new QueryClient({
defaultOptions: {
queries: {
queryFn: defaultQueryFn,
},
},
})

bootstrapApplication(MyAppComponent, {
providers: [provideAngularQuery(queryClient)],
})

export class PostsComponent {
// All you have to do now is pass a key!
postsQuery = injectQuery<Array<Post>>(() => ({
queryKey: ['/posts'],
}))
// ...
}

export class PostComponent {
// You can even leave out the queryFn and just go straight into options
postQuery = injectQuery<Post>(() => ({
enabled: this.postIdSignal() > 0,
queryKey: [`/posts/${this.postIdSignal()}`],
}))
// ...
}
```

[//]: # 'Example'
33 changes: 33 additions & 0 deletions docs/angular/guides/dependent-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
id: dependent-queries
title: Dependent Queries
ref: docs/react/guides/dependent-queries.md
replace: { 'useQuery': 'injectQuery', 'useQueries': 'injectQueries' }
---

[//]: # 'Example'

```ts
// Get the user
userQuery = injectQuery(() => ({
queryKey: ['user', email],
queryFn: getUserByEmail,
}))

// Then get the user's projects
projectsQuery = injectQuery(() => ({
queryKey: ['projects', this.userQuery.data()?.id],
queryFn: getProjectsByUser,
// The query will not execute until the user id exists
enabled: !!this.userQuery.data()?.id,
}))
```

[//]: # 'Example'
[//]: # 'Example2'

```ts
// injectQueries is under development for Angular Query
```

[//]: # 'Example2'
69 changes: 69 additions & 0 deletions docs/angular/guides/disabling-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
id: disabling-queries
title: Disabling/Pausing Queries
ref: docs/react/guides/disabling-queries.md
replace: { 'useQuery': 'injectQuery' }
---

[//]: # 'Example'

```ts
@Component({
selector: 'todos',
template: `<div>
<button (click)="query.refetch()">Fetch Todos</button>
@if (query.data()) {
<ul>
@for (todo of query.data(); track todo.id) {
<li>{{ todo.title }}</li>
}
</ul>
} @else {
@if (query.isError()) {
<span>Error: {{ query.error().message }}</span>
} @else if (query.isLoading()) {
<span>Loading...</span>
} @else if (!query.isLoading() && !query.isError()) {
<span>Not ready ...</span>
}
}
<div>{{ query.isLoading() ? 'Fetching...' : '' }}</div>
</div>`,
})
export class TodosComponent {
query = injectQuery(() => ({
queryKey: ['todos'],
queryFn: fetchTodoList,
enabled: false,
}))
}
```

[//]: # 'Example'
[//]: # 'Example2'

```ts
@Component({
selector: 'todos',
template: `
<div>
// 馃殌 applying the filter will enable and execute the query
<filters-form onApply="filter.set" />
<todos-table data="query.data()" />
</div>
`,
})
export class TodosComponent {
filter = signal('')

todosQuery = injectQuery(() => ({
queryKey: ['todos', this.filter()],
queryFn: () => fetchTodos(this.filter()),
enabled: !!this.filter(),
}))
}
```

[//]: # 'Example2'
11 changes: 11 additions & 0 deletions docs/angular/guides/does-this-replace-client-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
id: does-this-replace-client-state
title: Does TanStack Query replace global state managers?
ref: docs/react/guides/does-this-replace-client-state.md
replace:
{
'useQuery': 'injectQuery',
'useMutation': 'injectMutation',
'hook': 'function',
}
---
5 changes: 5 additions & 0 deletions docs/angular/guides/filters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
id: filters
title: Filters
ref: docs/react/guides/filters.md
---
16 changes: 16 additions & 0 deletions docs/angular/guides/important-defaults.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
id: important-defaults
title: Important Defaults
ref: docs/react/guides/important-defaults.md
replace:
{
'React': 'Angular',
'react-query': 'angular-query',
'useQuery': 'injectQuery',
'useInfiniteQuery': 'injectInfiniteQuery',
'useMemo and useCallback': 'setting signal values',
}
---

[//]: # 'Materials'
[//]: # 'Materials'

0 comments on commit 60cbd75

Please sign in to comment.