markForCheck()和detectChanges()有什么区别 [英] What's the difference between markForCheck() and detectChanges()

查看:337
本文介绍了markForCheck()和detectChanges()有什么区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

ChangeDetectorRef.markForCheck()ChangeDetectorRef.detectChanges()有什么区别?

我只找到了关于SO的信息有关NgZone.run()之间的区别,但没有找到这两个功能之间的区别./p>

对于仅参考文档的答案,请举例说明一些实际情况,以供选择.

解决方案

来自文档:

detectChanges():无效

检查更改检测器和它的孩子.

这意味着,如果您的模型(您的类)内部发生了任何更改,但未反映视图,则可能需要通知Angular来检测这些更改(检测局部更改)并更新视图.

可能的情况是:

1-变更检测器与视图分离(请参阅

这通常意味着(从Angular2语言开始):

我看到您的模型更改是由我接受的一种方式(事件,XHR请求,setTimeout和...)引起的,然后我运行了更改检测以更新您的视图并完成了,但是您的代码中还有另一个函数再次更新了模型,我不想再次运行更改检测,因为不再有像AngularJS这样的肮脏检查:D,我们应该使用一种数据流方式!

您肯定会遇到此错误:P.

几种修复方法:

1- 正确的方法:确保更新在更改检测周期内(Angular2更新是一次发生的一种方法,请勿在此之后更新模型并将代码移至更好的位置)地点/时间).

2- 惰性方式:在该更新后运行detectChanges()以使angular2感到满意,这绝对不是最好的方式,但是当您问到有什么可能的情况时,这就是其中一种

这种方式是您的意思:我真诚地知道您运行了更改检测,但是我希望您再次执行此操作,因为在完成检查后,我必须即时更新某些内容.

3-将代码放入setTimeout中,因为setTimeout是按区域修补的,并且在完成后将运行detectChanges.


来自文档

markForCheck() : void

标记所有ChangeDetectionStrategy策略祖先进行检查.

当组件的 ChangeDetectionStrategy OnPush 时,这是最需要的.

OnPush本身的意思是,只有发生以下任何一种情况,才运行更改检测:

1-如果@Input属性的引用已完全更改,则该组件的@inputs之一已完全替换为新值,或简单地放置了它.

因此,如果您组件的 ChangeDetectionStrategy OnPush ,那么您就有了:

   var obj = {
     name:'Milad'
   };

然后您像这样更新/变异它:

  obj.name = "a new name";

这不会更新 obj 引用,因此更改检测不会运行,因此该视图不会反映更新/突变.

在这种情况下,您必须手动告诉Angular检查和更新视图(markForCheck);

因此,如果您这样做:

  obj.name = "a new name";

您需要执行以下操作:

  this.cd.markForCheck();

相反,下面将导致运行更改检测:

    obj = {
      name:"a new name"
    };

用新的{}完全替换了先前的obj;

2-触发了一个事件,例如单击或类似的事件,或者任何子组件都发出了一个事件.

像这样的事件:

  • 点击
  • Keyup
  • 订阅事件

简而言之:

  • 在运行了angular之后更新了模型时,请使用detectChanges()进行更改检测,或者如果根本没有更新,请使用detectChanges().

  • 如果使用的是OnPush,并且通过突变某些数据来绕过ChangeDetectionStrategy,或者您已经在 setTimeout 中更新了模型,请使用markForCheck();

What is the difference between ChangeDetectorRef.markForCheck() and ChangeDetectorRef.detectChanges()?

I only found information on SO as to the difference between NgZone.run(), but not between these two functions.

For answers with only a reference to the doc, please illustrate some practical scenarios to choose one over the other.

解决方案

From docs :

detectChanges() : void

Checks the change detector and its children.

It means, if there is a case where any thing inside your model (your class) has changed but it hasn't reflected the view, you might need to notify Angular to detect those changes (detect local changes) and update the view.

Possible scenarios might be :

1- The change detector is detached from the view ( see detach )

2- An update has happened but it hasn't been inside the Angular Zone, therefore, Angular doesn't know about it.

Like when a third party function has updated your model and you want to update the view after that.

 someFunctionThatIsRunByAThirdPartyCode(){
     yourModel.text = "new text";
 }

Because this code is outside of Angular's zone (probably), you most likely need to make sure to detect the changes and update the view, thus:

 myFunction(){
   someFunctionThatIsRunByAThirdPartyCode();

   // Let's detect the changes that above function made to the model which Angular is not aware of.
    this.cd.detectChanges();
 }

NOTE :

There are other ways to make above work, in other words, there are other ways to bring that change inside Angular change cycle.

** You could wrap that third party function inside a zone.run :

 myFunction(){
   this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
 }

** You could wrap the function inside a setTimeout :

myFunction(){
   setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
 }

3- There are also cases where you update the model after the change detection cycle is finished, where in those cases you get this dreaded error :

"Expression has changed after it was checked";

This generally means (from Angular2 language) :

I saw an change in your model that was caused by one of my accepted ways ( events, XHR requests, setTimeout, and ... ) and then I ran my change detection to update your view and I finished it, but then there was another function in your code which updated the model again and I don't wanna run my change detection again because there is no dirty checking like AngularJS anymore :D and we should use one way data flow!

You'll definitely come across this error :P .

Couple of ways to fix it :

1- Proper way : make sure that update is inside the change detection cycle ( Angular2 updates are one way flow that happen once, do not update the model after that and move your code to a better place/time ).

2- Lazy way: run detectChanges() after that update to make angular2 happy, this is definitely not the best way, but as you asked what are the possible scenarios, this is one of them.

This way you're saying : I sincerely know you ran the change detection, but I want you to do it again because I had to update something on the fly after you finished the checking.

3- Put the code inside a setTimeout, because setTimeout is patched by zone and will run detectChanges after it's finished.


From the docs

markForCheck() : void

Marks all ChangeDetectionStrategy ancestors as to be checked.

This is mostly needed when the ChangeDetectionStrategy of your component is OnPush.

OnPush itself means, only run the change detection if any of these has happened :

1- One of the @inputs of the component has been completely replaced with a new value, or simply put, if the reference of the @Input property has changed altogether.

So if ChangeDetectionStrategy of your component is OnPush and then you have :

   var obj = {
     name:'Milad'
   };

And then you update/mutate it like :

  obj.name = "a new name";

This will not update the obj reference ,hence the change detection is not gonna run, therefore the view is not reflecting the update/mutation.

In this case you have to manually tell Angular to check and update the view (markForCheck);

So if you did this :

  obj.name = "a new name";

You need to do this:

  this.cd.markForCheck();

Rather, below would cause a change detection to run :

    obj = {
      name:"a new name"
    };

Which completely replaced the previous obj with a new {};

2- An event has fired, like a click or some thing like that or any of the child components has emitted an event.

Events like :

  • Click
  • Keyup
  • Subscription events
  • etc.

So in short :

  • Use detectChanges() when you've updated the model after angular has run it's change detection, or if the update hasn't been in angular world at all.

  • Use markForCheck() if you're using OnPush and you're bypassing the ChangeDetectionStrategy by mutating some data or you've updated the model inside a setTimeout;

这篇关于markForCheck()和detectChanges()有什么区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆