我读了很多文章,但仍然不明白角度变化检测的一些情况。我得到以下示例: Angular 应用程序在所有组件中实现了 OnInit、AfterViewInit、DoCheck、AfterViewChecked:
仅在父级中我实现了流行的加载示例(以及 HTML 中的
*ngIf="isLoading"
):
export class AppComponent
implements OnInit, AfterViewInit, DoCheck, AfterViewChecked
{
isLoading = false;
constructor(private changeDetectorRef: ChangeDetectorRef) {}
ngAfterViewInit(): void {
this.isLoading = true;
console.log('parent - after view init');
}
ngAfterViewChecked(): void {
console.log('AFTER CHECK');
}
ngDoCheck(): void {
console.log('parent - do check');
}
ngOnInit(): void {
console.log('parent - init');
}
}
输出(不加载
this.isLoading = true;
)是:
parent - init
parent - do check
Child - init
Child - do check
DeepChild - init
DeepChild - do check
DeepChild - after view init
DeepChild - after check
Child - after view init
Child - after check
parent - after view init
parent - after view check
<with assigning loading value as in code above here I got expression changed error>
<and after that I got some more checks generated>
parent - do check
Child - do check
DeepChild - do check
DeepChild - after check
Child - after check
parent - after check
我有以下问题:
为什么我会收到额外的支票?
如果我添加加载,我会收到错误
ExpressionChangedAfterItHasBeenCheckedError
,我知道这是在检查视图之后,但我得到了额外的检查,所以为什么问题仍然存在?
如果我添加changeDetectorRef并手动检测更改,问题就解决了,但为什么呢?好吧,我触发了下一个检测,但是在私钥中检查后仍然有一个表达式发生了变化,那么为什么触发下一个只是解决它呢?
此 detectorChanges 仅在子组件中触发
doCheck
。尽管我在父组件中触发它,但它并没有在父组件中调用检测?
这里是 stackblitz 参考 - https://stackblitz.com/edit/angular-ivy-m6hbk2?file=src%2Fapp%2Fapp.component.ts
您希望应用程序中的单向数据流。在组件生命周期中,Angular 将数据从父级渲染到子级。 Angular 有一个开发检查,以便在该周期中渲染整个视图后,它会继续运行从父级到子级的整个数据渲染以确保没有任何更改。在生产中,第二次检查不会运行,并且更改的数据不会呈现为在该检测周期中已更改。
如果您设置了
isLoading = false;
并且渲染了父级,然后您立即更改了该值,那么您就破坏了这个单向数据流。尽管您之后更改了此设置,但孩子们仍将被渲染为 isLoading = false;
。强制更改检测在父级上运行两次可以“解决”问题,因为父级将使用可在生产中使用的更新值进行渲染。但这是一种反模式,引入检测周期来修复不良数据流。
在使用 Angular 4 年多的时间里,我从未在任何代码中使用过
ngDoCheck
,我不建议花很长时间来尝试理解它。