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

Mar*_*rgh 4 data-binding angular2-changedetection angular

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

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

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

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

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

考虑这个父组件,它有一个这样的模板:

<cv-messages [messages]="informationMessages"></cv-messages>
Run Code Online (Sandbox Code Playgroud)

以及带有这段代码的打字稿文件:

informationMessages: InformationMessageType[] = [];

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

        .... // parsing stuff

        this.informationMessages = informationMessages;
        // add markForCheck() here
    });
}
Run Code Online (Sandbox Code Playgroud)

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

ngOnChanges(changes) {
    console.log(this.constructor.name ' CHANGE:', changes);
}
Run Code Online (Sandbox Code Playgroud)

更新:

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

Ste*_*pUp 5

正如 Angular 文档所说:

当视图使用 OnPush (checkOnce) 更改检测策略时,将视图显式标记为已更改,以便可以再次检查。

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

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

更新:

有两种类型ChangeDetectionStrategy

OnPush: 0 使用 CheckOnce 策略,这意味着自动更改检测被停用,直到通过将策略设置为默认 (CheckAlways) 重新激活。仍然可以显式调用更改检测。此策略适用于所有子指令,不能被覆盖。

默认值:1 使用默认的 CheckAlways 策略,其中更改检测是自动的,直到明确停用。

所以,当你使用OnPush自动变化检测被停用,并有必要将其标记为更改,以便它可以再次检查视图。