为什么我需要添加 markForCheck() 来触发 Angular 中的变化检测?

Why do i need to add markForCheck() to trigger change detection in Angular?

我不太明白为什么我需要在下面的代码中添加 markForCheck() 以使更改可见。为什么我的@Input() 没有触发变化检测?

我正在将我的项目重构为 OnPush。这两个组件都启用了 OnPush。据我了解,当启用此功能并更改 Input()(如 messages)时,会触发更改检测。

在下面的代码中,我通过 graphqlService 进行了调用。当我接到电话时,我对传入的数据进行了一些解析,然后将其设置为 informationMessages 属性,它通过其 messages [=] 绑定到子组件 cv-messages 49=].

结果是 ngOnChanges 函数仅在 informationMessages 属性 初始化时调用一次。但不是当最终解析的数据设置为它时。

如果我添加 markForCheck() 它工作正常。

考虑这个父组件,模板如下:

<cv-messages [messages]="informationMessages"></cv-messages>

以及包含这段代码的打字稿文件:

informationMessages: InformationMessageType[] = [];

ngOnInit() {
    this.graphqlService.loadInformationMessages().subscribe(data => {
        const informationMessages: InformationMessageType[] = data;

        .... // parsing stuff

        this.informationMessages = informationMessages;
        // add markForCheck() here
    });
}

消息组件有一个 ngOnChanges 函数,如下所示:

ngOnChanges(changes) {
    console.log(this.constructor.name ' CHANGE:', changes);
}

更新:

您可以在下面的答案评论中找到解决方案。基本上,当 @Input() 异步更改时,更改检测是 NOT 触发的。所以在这种情况下,我们需要添加一个 markForCheck() 来强制进行更改检测。

As Angular docs says:

When a view uses the OnPush (checkOnce) change detection strategy, explicitly marks the view as changed so that it can be checked again.

当输入已更改或视图中已触发事件时,组件通常被标记为脏(需要重新渲染)。调用此方法可确保即使未发生这些触发器也能检查组件。

因此需要此方法来将组件标记为脏以重新渲染。

更新:

有两种ChangeDetectionStrategy:

OnPush: 0 Use the CheckOnce strategy, meaning that automatic change detection is deactivated until reactivated by setting the strategy to Default (CheckAlways). Change detection can still be explicitly invoked. This strategy applies to all child directives and cannot be overridden.

Default: 1 Use the default CheckAlways strategy, in which change detection is automatic until explicitly deactivated.

因此,当您使用 OnPush 时,自动更改检测将被停用,并且有必要将视图标记为已更改,以便再次检查。