Angular markForCheck未触发子ngOnChanges生命周期挂钩

Angular markForCheck未触发子ngOnChanges生命周期挂钩,angular,typescript,Angular,Typescript,我有两个部分;父级和子级,通过@Input和@Output属性装饰器进行通信。i、 e.父对象将名为config的输入对象传递给子对象,并侦听子对象发出的事件 其中配置对象类型为 config:any = { a: number; b: number; } 这里简单介绍一下config.a由子级管理,因此父级从不更改它,同样地config.b由父级管理 在建立这个交流模型时,我观察到以下奇怪的行为 父级通过属性绑定传递所需的输入,即 [config]=“config” 通常情况

我有两个部分;父级和子级,通过
@Input
@Output
属性装饰器进行通信。i、 e.父对象将名为
config
的输入对象传递给子对象,并侦听子对象发出的事件

其中配置对象类型为

config:any = {
    a: number;
    b: number;
}
这里简单介绍一下
config.a
由子级管理,因此父级从不更改它,同样地
config.b
由父级管理

在建立这个交流模型时,我观察到以下奇怪的行为

  • 父级通过属性绑定传递所需的输入,即
  • [config]=“config”

    通常情况下,属性绑定只能以一种方式工作,但在这里它的行为是双向绑定。i、 e.当父项在其自身范围内更新
    config.b
    时,子项的配置也会更新,反之亦然

  • 子级希望收到父级对其自己的配置对象所做的任何更改的通知,因此它实现了
    OnChanges
    生命周期挂钩,以执行一些内部功能。但是因为一个对象在本质上是不可变的,所以孩子不会被通知这些变化,除非

    • 它更新配置对象引用,如下所示:

      this.config = new Config()
      
    • 或者使用
      onPush
      更改检测策略,并调用以下函数通知孩子更改

      changeDetectorRef.markForCheck()
      
  • 但是当我尝试
    changedtectorref.markForCheck()时
    孩子的
    ngOnChanges
    生命周期挂钩永远不会触发


    有人能解释这两个奇怪问题背后的原因吗。我在plunker中复制了这两个问题以供参考。

    基本上,Angular只进行“脏”检查。意味着复杂的对象没有被正确检查

    下面是一个链接,指向更好地解释它的人:

    另一个解决方案是创建一个EventEmitter,您可以通过它进行绑定,并手动告诉父级子级发生了更改

    例如:

    @Output() onChange: EventEmitter<any> = new EventEmitter<any>();
    
    public triggerChanges() {
       this.onChange.emit()
    }
    

    @Output()onChange:EventEmitter我在这里添加了ngDoCheck,唯一的缺点是您必须比较值是否真的被重新分配了。

    我要问的是,即使我使用markForCheck手动告诉变更检测器我已经更新了某些内容,它仍然不会触发子项的ngochange。为了支持这个论点,你可以参考plunkr。另外,config对象在两个对象之间始终保持同步,它只是一个ngonchange,永远不会被触发。@SaifUllah不幸的是,mark for check并不总是触发lifecycle钩子,它所做的是触发一个更改检测循环。在此循环中,它比较objectA和objectB。因为对象是复杂的,它不能正确地进行比较,然后看到“没有更改”,因此没有调用生命周期挂钩。这就是为什么您经常使用这里提到的其他钩子:或者手动对EventEmitter执行某些操作,因为我想将更改从父级传播到子级,这样事件发射器就不会成为这里的选项。这意味着我唯一的机会是使用服务或通过重新初始化来更新对象引用。另一件需要注意的是,子对象的配置确实得到了更新,这不意味着change detector成功地检测到了此更改。仅此而已,change detector无法检测到这样的更改。例如:public numberA=0。然后,numberA=1,后跟.markForCheck()。该循环将比较新旧数值a!==B号?火变了:什么也没发生。问题是复杂的对象很难比较,因此它们不可见,因此即使进行了更改,生命周期挂钩也不会触发。可以使用的另一个技巧(在我发送的链接中找到)是重新分配对象。或者,object=object.assign({},object);
    <app-my-component (onChange)="event"></app-my-component>