typescript 为什么ngOnChange无法检测@Input元素更改,而ngOnDetect能够检测

ltskdhd1  于 2023-01-27  发布在  TypeScript
关注(0)|答案(3)|浏览(175)

考虑一下plunker
注意:要观察效果,您必须在输入链接后重新运行应用程序

import {Component, OnInit, Input, OnChanges, DoCheck} from 'angular2/core'

@Component({
  selector: 'sub',
  template: `
    <li  *ngFor="#elem of sub_list">
      <div>{{elem['name']}}</div>
    </li>
    `
})
export class Sub {

  @Input()
  sub_list: Object[];

  ngOnInit(){
    console.log('init');
    console.log(this.sub_list);
  } 

  ngOnChanges(){
    console.log('change');
    console.log(this.sub_list);
  }

  ngDoCheck() {
    console.log('check');
    console.log(this.sub_list);
  }

}
@Component({
  selector: 'my-app',
  template: `
    <div>
      <sub
        [sub_list]="my_list"
      >
      </sub>

    </div>

    `,
  directives: [Sub]
})
export class App {

  my_list: Object[] = [];

  ngOnInit() {
      var vm = this;

    setTimeout(function() {
          for(var i = 0; i < 100; i++) {

        vm.my_list.push({
          'index' : i,
          'name'  : i
        });
      }
    }, 100);

  }
}

如果我试图在SubngOnChange中打印出this.sub_list,浏览器会输出一个空列表。
但是,我们可以看到ngDoCheck仍然正确地捕获了更改。
这有什么特别的原因吗?

vdzxcuhz

vdzxcuhz1#

在你的例子中,ngOnChanges不会被调用来更新数组。事实上,Angular2会根据引用来检测更新。我的意思是,如果整个数组的引用没有改变(使用push方法在其中添加元素时就是这种情况),ngOnChanges方法就不会被调用。
在您的示例中,当调用ngOnChanges时,您的数组为null,因为它是在设置input元素之前调用的。
在这种情况下,有两种方法可以检测更改:

  • 使用slice(push之后)或concat等方法更新整个数组引用。
this.myArray.push({...});
this.myArray.push = this.myArray.push.slice();
  • 使用ngDoCheck方法和IterableDiffers类来手动检查更新。2该类允许你注册回调函数,以便在数组中添加(或删除)元素时得到通知。

有关详细信息,请参阅以下链接:

x4shl7ld

x4shl7ld2#

好了,我明白了。当你用空数组初始化类字段时,ngOnChanges被触发,然后你在超时回调内更新数组,因为没有检测到Thierry正确指向的更改。
Angular包含zone.js库,可以跟踪应用中的所有异步事件。Zone检测到在某处执行了超时回调,并触发ngDoCheck循环,您将获得正确的日志。
参见plunkr

8ljdwjyq

8ljdwjyq3#

当我们有相同的引用时,ngOnChanges不会检测嵌套对象的变化,解决方案是每次创建新的对象引用:
const object = Object.assign({},oldObject)

相关问题