Angular2用于阵列突变的OnPush变化检测

Angular2用于阵列突变的OnPush变化检测,angular,angular2-changedetection,Angular,Angular2 Changedetection,我有一个data table component()项目,我们将项目从Angular的传统更改检测更改为OnPush,以优化渲染速度 一旦实施了新的更改检测策略,就会出现一个bug,该bug引用了数据对象发生变化时未更新的表,例如对象的属性更新引用:。对于这种类型的需求,例如对大型数据集合(如股票行情器)中单个属性的内联编辑或外部数据更改,可以创建一个强大的用例 为了解决这个问题,我们添加了一个名为trackByProp的定制trackBy属性检查器。参考文献:。不幸的是,这一解决办法没有解决问

我有一个data table component()项目,我们将项目从Angular的传统更改检测更改为
OnPush
,以优化渲染速度

一旦实施了新的更改检测策略,就会出现一个bug,该bug引用了数据对象发生变化时未更新的表,例如对象的属性更新引用:。对于这种类型的需求,例如对大型数据集合(如股票行情器)中单个属性的内联编辑或外部数据更改,可以创建一个强大的用例

为了解决这个问题,我们添加了一个名为
trackByProp
的定制trackBy属性检查器。参考文献:。不幸的是,这一解决办法没有解决问题

在under live reloading上,您可以看到上面提交中引用的演示正在运行,但在单击触发更改检测之前不会更新表

组件的结构类似于:

表格>正文>行组>行>单元格

所有这些组件都实现了
OnPush
。我在行setter中使用getter/setter来触发页面重新计算,如图所示

对于那些实现此模式的人,我们希望继续使用
OnPush
更改检测,但是,作为一个具有多个使用者的开源项目,我们可以为屏幕上的可见行值提供某种自定义检查功能


总之,
trackBy
不会触发行单元格值的更改检测,实现这一点的最佳方法是什么?

Angular2更改检测不会检查数组或对象的内容

一个很有技巧的解决方法是在变异后创建数组的副本

this.myArray.push(newItem);
this.myArray=this.myArray.slice();
这样
This.myArray
引用不同的数组实例,Angular将识别更改

另一种方法是使用
IterableDiffer
(用于数组)或
keyvaluedifference
(用于对象)

//注入不同的实现
构造函数(不同:KeyValueDifferents){
//存储要与之比较的初始值
this.difference=differences.find({}).create(null);
}
@输入()数据:任意;
ngDoCheck(){
var changes=this.difference.diff(this.data);//检查更改
if(更改和初始化此文件(&T){
//如果发现更改,请执行某些操作
}
}

另请参见您可能希望使用
ChangeDetectorRef
中的
markForCheck
方法


我确实有一个类似的问题,我有一个包含大量数据的组件,并且在每个变更检测周期都重新检查它们,这不是一个选项。但是,当我们从URL中查看一些属性并相应地更改视图中的内容时,使用
onPush
我们的视图不会(自动)刷新

因此,在构造函数中,使用DI获取
changeDetectorRef
的实例:

构造函数(专用changeDetectorRef:changeDetectorRef)

在需要触发变更检测的任何地方:

this.changeDetectorRef.markForCheck();

我也面临着类似的问题,为了优化我的应用程序性能,我不得不使用changeDetection.OnPush策略。因此,我将它注入到父组件和子组件的构造函数中,changeDetectorRef

    export class ChildComponent{
     @Input myData: myData[];
     constructor(private _cd : ChangeDetectorRef){
          }
       changeInputVal(){
        this.myData = ....something new value with new reference;
        this._cd.markForCheck(); // To force angular to trigger its change detection now
       }
    }
类似地,在子组件中,注入了changeDetectorRef的实例

    export class ChildComponent{
     @Input myData: myData[];
     constructor(private _cd : ChangeDetectorRef){
          }
       changeInputVal(){
        this.myData = ....something new value with new reference;
        this._cd.markForCheck(); // To force angular to trigger its change detection now
       }
    }
每个异步功能都会触发角度变化检测:-

  • 任何DOM事件,如单击、提交、鼠标悬停
  • 有XHR电话吗
  • 任何计时器,如setTimeout()等
所以,这会减慢应用程序的速度,因为即使我们拖动鼠标,angular也会触发changeDetection。对于跨越多个组件的复杂应用程序,这可能是一个主要的性能瓶颈,因为angular具有这种树型的父子变更检测策略。 为了避免这种情况,我们最好使用OnPush策略,并在看到参考变化时强制触发angular的变化检测

其次,在OnPush策略中,应该非常小心,它只会在对象引用发生更改时触发更改,而不仅仅是对象属性值(即角度更改)表示“新引用”

例如:-

    obj = { a:'value1', b:'value2'}'
    obj.a = value3;
“obj”中“a”的属性值可能已更改,但obj仍指向同一参考,因此此处不会触发角度更改检测(除非您强制触发); 要创建新引用,需要将对象克隆到另一个对象中,并相应地指定其属性


为了进一步理解,请阅读有关不可变数据结构、更改检测的内容,稍后再回答,但另一个解决方法是在变异后使用扩展运算符。。
myArr=[…myArr]
myObj={…myObj}

这甚至可以在变异时完成:
myArr=myMutatingArr([…myArr])
,因为参数作为数组的新引用,使变量采用新引用,因此调用角度检查

如上所述,如果您更改参考,将进行检查,在任何情况下都可以使用spread运算符来精确执行该操作

尽管数据结构中的嵌套数据结构要求将引用更改到嵌套级别,但要小心。您必须进行一次迭代,以返回排列内部的排列,例如:

myObj = {...myObj, propToChange: { ...myObj.propToChange,
        nestedPropArr: [ ...myObj.propToChange.nestedPropArr ]
    }
}

如果需要对对象等进行迭代,这可能会变得复杂。希望这对别人有帮助

问题应该包括允许重现问题的代码。
ngDoCheck
在我调用类似click的事件之前不会运行。另外,我注意到,
*ngFor
中已经有自定义跟踪功能,为什么它无法检测到?我是