mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs: Add after*Render to Component Lifecycle guide (#51291)
PR Close #51291
This commit is contained in:
committed by
Dylan Hunn
parent
899e51ad8e
commit
95387047fd
@@ -138,6 +138,97 @@ data$ = http.get('...').pipe(takeUntilDestroyed());
|
||||
|
||||
By default, `takeUntilDestroyed` must be called in an [injection context](/guide/dependency-injection-context) so that it can access `DestroyRef`. If an injection context isn't available, you can explicitly provide a `DestroyRef`.
|
||||
|
||||
## Reading and writing the DOM
|
||||
|
||||
Sometimes it's necessary to use browser-only APIs to manually read or write the DOM. This can be challenging to do with the [lifecycle events](#lifecycle-event-sequence) above, as they will also run during [server-side rendering and pre-rendering](guide/glossary#server-side-rendering). For this purpose, Angular provides `afterRender` and `afterNextRender`. These functions can be used unconditionally, but will only have an effect on the browser. Both functions accept a callback that will run after the next [change detection](/guide/glossary#change-detection) cycle (including any nested cycles) has completed.
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
`afterRender` and `afterNextRender` are available for [developer preview](/guide/releases#developer-preview). They are ready for you to try, but they might change before they are stable.
|
||||
|
||||
</div>
|
||||
|
||||
| Function | Purpose | Timing |
|
||||
| ------ | ------- | ------ |
|
||||
| `afterNextRender` | Perform one-time initialization, or observe a single, specific change to the DOM. <br /> <div class="alert is-helpful">As a rule of thumb, you should use `afterRender` instead if you need to manually read or write any layout data such as size or location.</div> See details in [One-time initialization](#one-time-initialization) in this document. | _Once_ after the next change detection cycle. |
|
||||
| `afterRender` | Synchronize state with the DOM. See details in [Handling synchronization](#handling-synchronization) in this document. | After _every_ change detection cycle that follows. |
|
||||
|
||||
### One-time initialization
|
||||
|
||||
Generally, you will want to use `afterNextRender` to perform any one-time initialization, such as for a third-party library, or for browser-only APIs.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-chart-cmp',
|
||||
template: `<div #chart>{{ ... }}</div>`,
|
||||
})
|
||||
export class MyChartCmp {
|
||||
@ViewChild('chart') chartRef: ElementRef;
|
||||
chart: MyChart|null;
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.chart = new MyChart(this.chartRef.nativeElement);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Instead of attempting to recreate their behaviors with `afterRender`, you should prefer to use built-in browser APIs like `ResizeObserver` and `IntersectionObserver` wherever possible. You can use `afterNextRender` to safely initialize such APIs on the browser only.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-cmp',
|
||||
template: `<span #content>{{ ... }}</span>`,
|
||||
})
|
||||
export class MyComponent {
|
||||
resizeObserver: ResizeObserver|null = null;
|
||||
@ViewChild('content') contentRef: ElementRef;
|
||||
|
||||
constructor() {
|
||||
afterNextRender(() => {
|
||||
this.resizeObserver = new ResizeObserver(() => {
|
||||
console.log('Content was resized');
|
||||
});
|
||||
|
||||
this.resizeObserver.observe(this.contentRef.nativeElement);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.resizeObserver?.disconnect();
|
||||
this.resizeObserver = null;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<div class="alert is-important">
|
||||
|
||||
As a rule of thumb, `afterNextRender` should be used to observe _discrete_ changes to the DOM, such as element creation or deletion. For manually reading or writing data that tends to change frequently, such as size or location, you should generally prefer to use `afterRender` instead.
|
||||
|
||||
</div>
|
||||
|
||||
### Handling synchronization
|
||||
|
||||
As an escape hatch for when the browser does not provide a better API to do so, you can use `afterRender` to perform any additional read or writes to the DOM every time Angular finishes mutating it.
|
||||
|
||||
```ts
|
||||
@Component({
|
||||
selector: 'my-cmp',
|
||||
template: `<span #content>{{ ... }}</span>`,
|
||||
})
|
||||
export class MyComponent {
|
||||
@ViewChild('content') contentRef: ElementRef;
|
||||
|
||||
constructor() {
|
||||
afterRender(() => {
|
||||
const elem = this.contentRef.nativeElement;
|
||||
console.log(`content position: (${elem.offsetLeft}, ${elem.offsetTop})`);
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## General examples
|
||||
|
||||
The following examples demonstrate the call sequence and relative frequency of the various lifecycle events, and how the hooks can be used separately or together for components and directives.
|
||||
|
||||
Reference in New Issue
Block a user