简体   繁体   English

onPush检测策略在角度8中不起作用

[英]onPush Detection strategy not working in angular 8

I am creating an application in angular 8 and presently working on dashboard module where i have a scenario where onPush Strategy doesn't seems to be working i will be explaining my scenario with div structure if anyone can help me on this. 我正在用angular 8创建一个应用程序,目前正在仪表板模块上工作,那里有一个onPush Strategy似乎无法正常工作的场景,如果有人可以帮助我,我将用div结构解释我的场景。

<div class="parent" *ngFor="dashcontent of dashbboardsData">

<app-widget-body [widget]="dashcontent.widget"></app-widget-body>


</div>


<div class="sidebar"> 

<app-sidebar [(selectedWidget)]="dashbboardsData[0].widget">

<app-widget-settings [(widget)]="selectedWidget"></app-settings>

</app-sidebar>

</div>

Above is the scenario where i am changing widget.widgetName in app-widget-settings component, where app-widget-settings consist of text box which is bind with widget.widgetName using ngModel . 上面是我在app-widget-settings组件中更改widget.widgetName的场景,其中app-widget-settings包含文本框,该文本框使用ngModelwidget.widgetName绑定。

<input type="text" [(ngModel)]="widget.widgetName">

here but my changes is not reflected in app-widget-body component where i am using 在这里,但我的更改未反映在我使用的app-widget-body组件中

changeDetection: ChangeDetectionStrategy.OnPush

if i am removing changeDetection from app-widget-body then changes are reflected. 如果我要从app-widget-body中删除changeDetection,则会反映出更改。

So in above what should we use so that changes when done in app-widget-settings component are reflected in app-widget-body component and i want to use ChangeDetectionStrategy.OnPush. 因此,在上面我们应该使用什么,以便将在app-widget-settings组件中完成时的更改反映在app-widget-body组件中,我想使用ChangeDetectionStrategy.OnPush。

Below is the link for stackblitz 以下是stackblitz的链接

https://stackblitz.com/edit/angular-gjdjzg?file=src%2Fapp%2Fapp.component.ts https://stackblitz.com/edit/angular-gjdjzg?file=src%2Fapp%2Fapp.component.ts

This is actually the expected behavior. 这实际上是预期的行为。

Each and every component has her own Change Detection Ref, and when you changing the strategy to OnPush strategy you have to remember that in order to cause the change detector to "tick" you have to pass a new reference of your input. 每个组件都有自己的变更检测参考,将策略更改为OnPush策略时,必须记住,要使变更检测器“打勾”,必须传递输入的新参考。

In this case, you just edit one of the properties of the widget, but didn't really change his reference. 在这种情况下,您只需编辑窗口小部件的属性之一,但并没有真正更改其引用。

Try to emit an event every time you change the widget object, and then, in the container component just return a new object overriding the change. 尝试在每次更改窗口小部件对象时发出一个事件,然后在容器组件中仅返回一个覆盖更改的新对象。 Something like: 就像是:

onNameChange(name: string){
   this.widget = {...this.widget, widgetName: name}
}

You need to "bubble up" changes to the Dashboard component for it to reload ( change its reference ) its array of widgets: 您需要“填充”对仪表板组件的更改,以使其重新加载( 更改其引用 )其小部件数组:

https://stackblitz.com/edit/angular-mzxcbd https://stackblitz.com/edit/angular-mzxcbd

It is tedious and not very pretty. 这很乏味,也不是很漂亮。 In general it is not recommended for deeply nested objects. 通常,不建议将其用于深度嵌套的对象。 A good alternative approach is to use the redux pattern with NGRX for example. 一个很好的替代方法是将Redux模式与NGRX一起使用。 A central store holds your data and any component can access it, independantly from its hierarchy. 中央存储可以保存您的数据 ,任何组件都可以独立于其层次结构来访问它。 I highly recommend it. 我强烈推荐它。

When you use ChangeDetectionStrategy.OnPush, you have to follow a rule ' Every variable that does not come from @Input(), is used in template and may be changed during lifetime of component, should be in template as a stream(Observable) with pipe async ' 当您使用ChangeDetectionStrategy.OnPush时,必须遵循一个规则' 不是来自@Input()每个变量都在模板中使用,并且可能在组件的生命周期内更改,因此应在模板中作为stream(Observable)使用管道异步 '

Angular also has 3 classes for reactive data: Angular还具有3种用于反应数据的类:

  • FormArray - for arrays FormArray-用于数组
  • FormGroup - for maps FormGroup-用于地图
  • FormControl - for simple values FormControl-用于简单值

Notice that you should only modify data in theese classes only via provided APIs, like FormControl.setValue(value) for them to emit change event, which will tell async pipe to trigger change detection cycle 请注意,您仅应仅通过提供的API修改这些ese类中的数据,例如FormControl.setValue(value),以使它们发出更改事件,这将告诉异步管道触发更改检测周期

In your case I would use FormArray of FormGroup elements, which would have FormControl for each field. 在您的情况下,我将使用FormGroup的FormGroup元素,每个字段都具有FormControl。

Access to fields would be like 访问字段就像

<div class="parent" *ngFor="widgetFormGroupIndex of widgetIndexList">
  {{ dataFormArray.at(widgetFormGroupIndex).get('widgetName').valueChanges | async }}
</div>

Also you should use directive from ReactiveFormsModule in your input, like this 同样,您应该在输入中使用ReactiveFormsModule中的指令,像这样

<input type="text" [formControl]="dataFormArray.at(widgetFormGroupIndex).get('widgetName')">

For further info read https://angular.io/guide/reactive-forms 有关更多信息,请阅读https://angular.io/guide/reactive-forms

Also note that you shouldn't call methods in templates(it calls them in every change detection cycle), the code uses methods for simplicity. 还要注意,您不应该在模板中调用方法(它在每个更改检测周期都调用它们),代码使用方法是为了简化。 Instead of func calls you should either create pure pipes(for more info read here https://angular.io/guide/pipes ) or precompute func call results in your component.ts file, then use results in template 而不是func调用,您应该创建纯管道(有关更多信息,请参见https://angular.io/guide/pipes ),或者在component.ts文件中预先计算func调用结果,然后在模板中使用结果

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM