【问题标题】:Why do i need to add markForCheck() to trigger change detection in Angular?为什么我需要添加 markForCheck() 来触发 Angular 中的更改检测?
【发布时间】:2020-04-02 08:26:18
【问题描述】:

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

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

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

结果是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
    });
}

messages 组件有一个这样的 ngOnChanges 函数:

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

更新:

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

【问题讨论】:

    标签: angular data-binding angular2-changedetection


    【解决方案1】:

    As Angular docs says:

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

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

    所以需要这个方法来将一个组件标记为脏的需要重新渲染。

    更新:

    ChangeDetectionStrategy有两种类型:

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

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

    因此,当您使用OnPush 时,自动更改检测被停用,需要将视图标记为已更改,以便再次对其进行检查。

    【讨论】:

    • 那么你的意思是 Angular 错过了这个很脏的属性,所以我需要自己明确设置它?但是为什么 Angular 会错过这个肮脏的变化呢?我做错了吗?
    • @MartijnvandenBergh 你做得对。请看我更新的答案
    • 谢谢,非常清楚。仍然觉得我必须手动执行此操作很奇怪,因为我正在更改 @Input()(informationMessage 绑定到 [messages]),我认为这会强制使用 OnPush 组件进行更改检测?但我想我的理解是错误的。
    • @MartijnvandenBergh 这可能是因为您在ngOnInit()上执行的异步操作
    • @MartijnvandenBergh 在您的ngOnInit() 中,您执行旨在设置informationMessages 属性的操作。问题是 Angular 不会刷新视图,因为您“异步”设置了此属性,因此视图不会更新,因为没有 @Input 已更改。通常,您使用直接使用 html 中的@Input 属性的组件设置 OnPush,这样每当向组件推送新值时,Angular 就知道何时启动检测周期。在这种情况下,您手动设置了一个属性,而 Angular 不知道该怎么做。这就是您手动启动检测的原因
    猜你喜欢
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2021-04-09
    • 1970-01-01
    • 2019-10-04
    • 1970-01-01
    • 2017-12-27
    • 2017-06-02
    相关资源
    最近更新 更多