ChangeDetectorRef.markForCheck()
和之间有什么区别ChangeDetectorRef.detectChanges()
?
我只找到了关于SO的信息NgZone.run()
,但没有找到这两个功能之间的区别。
对于仅参考文档的答案,请举例说明一些实际情况,以供选择。
ChangeDetectorRef.markForCheck()
和之间有什么区别ChangeDetectorRef.detectChanges()
?
我只找到了关于SO的信息NgZone.run()
,但没有找到这两个功能之间的区别。
对于仅参考文档的答案,请举例说明一些实际情况,以供选择。
Answers:
从文档:
detectChanges():无效
这意味着,如果您的模型(您的类)内部发生了任何更改,但未反映视图,则可能需要通知Angular来检测这些更改(检测局部更改)并更新视图。
可能的情况可能是:
2-更新已发生,但尚未在Angular区域内,因此Angular对此一无所知。
就像第三方功能已更新您的模型,然后又要更新视图一样。
someFunctionThatIsRunByAThirdPartyCode(){
yourModel.text = "new text";
}
由于此代码位于Angular区域之外(可能),因此您很可能需要确保检测到更改并更新视图,因此:
myFunction(){
someFunctionThatIsRunByAThirdPartyCode();
// Let's detect the changes that above function made to the model which Angular is not aware of.
this.cd.detectChanges();
}
注意:
还有其他方法可以使上述工作正常进行,换句话说,还有其他方法可以将更改带入Angular更改周期。
**您可以将该第三方函数包装在zone.run中:
myFunction(){
this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
}
**您可以将函数包装在setTimeout中:
myFunction(){
setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
}
3-在某些情况下,您还需要在模型change detection cycle
完成后更新模型,在这种情况下,您会得到这个可怕的错误:
“检查后,表达已更改”;
这通常意味着(从Angular2语言开始):
我看到您的模型更改是由我接受的一种方式(事件,XHR请求,setTimeout和...)引起的,然后我运行了更改检测以更新您的视图,然后完成了它,但是还有另一种方法函数中的代码再次更新了模型,并且我不想再次运行更改检测,因为不再有像AngularJS这样的脏检查了:D,我们应该使用一种数据流方式!
您肯定会遇到此错误:P。
修复它的几种方法:
1- 正确的方法:确保更新在变更检测周期之内(Angular2更新是一次发生的一种方法,请勿在此之后更新模型并将代码移至更好的位置/时间)。
2- 懒惰的方式:在该更新之后运行detectChanges()以使angular2感到满意,这绝对不是最好的方式,但是当您询问有什么可能的情况时,这就是其中一种。
这样您就说:我真诚地知道您运行了更改检测,但是我希望您再次执行此操作,因为在完成检查后,我必须即时更新某些内容。
3-将代码放入setTimeout
,因为它setTimeout
是按区域修补的,将detectChanges
在完成后运行。
来自文档
markForCheck() : void
这主要是在需要时ChangeDetectionStrategy你的组件是OnPush。
OnPush本身意味着,仅在发生以下任何一种情况时才运行更改检测:
1-如果@Input属性的引用已完全更改,则组件的@input之一已完全替换为新值,或者简单地放置了该内容。
所以,如果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-事件已触发,例如单击或类似的事件,或者任何子组件已发出事件。
像这样的事件:
简而言之:
detectChanges()
在angular运行之后更新模型时使用,它可以检测变化,或者根本不存在更新。
使用markForCheck()
如果您使用的OnPush和你绕过ChangeDetectionStrategy
通过突变的一些数据,或者你已经更新了内部模型的setTimeout ;
detectChanges
更新视图。请参阅此深入说明。
this.cdMode === ChangeDetectorStatus.Checked
它不会更新视图,那么这就是为什么要使用markForCheck的原因。
detectChanges
。cdMode
Angular中没有4.x.x
。我在我的文章中写到。很开心你喜欢。别忘了您可以在媒体上推荐它,也可以关注我:)
两者之间最大的区别是detectChanges()
实际上触发变更检测,而markForCheck()
不会触发变更检测。
该代码用于对组件树进行更改检测,从您触发其的组件开始detectChanges()
。因此,更改检测将针对当前组件及其所有子组件运行。Angular在中保存对根组件树的引用ApplicationRef
,当发生任何异步操作时,它会通过包装方法触发对该根组件的更改检测tick()
:
@Injectable()
export class ApplicationRef_ extends ApplicationRef {
...
tick(): void {
if (this._runningTick) {
throw new Error('ApplicationRef.tick is called recursively');
}
const scope = ApplicationRef_._tickScope();
try {
this._runningTick = true;
this._views.forEach((view) => view.detectChanges()); <------------------
view
这是根组件视图。正如我在“ 引导多个组件的含义是什么”中所述,可能有许多根组件。
@milad描述了您可能需要手动触发更改检测的原因。
就像我说的,这个家伙根本不会触发变更检测。它只是从当前组件向上扩展到根组件,并将其视图状态更新为ChecksEnabled
。这是源代码:
export function markParentViewsForCheck(view: ViewData) {
let currView: ViewData|null = view;
while (currView) {
if (currView.def.flags & ViewFlags.OnPush) {
currView.state |= ViewState.ChecksEnabled; <-----------------
}
currView = currView.viewContainerParent || currView.parent;
}
}
组件的实际更改检测未计划,但将来会发生时(作为当前或下一个CD周期的一部分),即使父组件视图已脱离更改检测器,也将对其进行检查。可以通过使用cd.detach()
或通过指定OnPush
更改检测策略来分离更改检测器。所有本机事件处理程序都将所有父组件视图标记为要检查。
这种方法通常在ngDoCheck
生命周期挂钩中使用。如果您认为这ngDoCheck
意味着正在检查您的组件,请阅读更多内容。阅读本文。
另请参阅有关Angular中的更改检测所需了解的所有内容。
markForCheck
。因此,如果您不使用异步管道,那可能就是您应该使用的管道。但是,请记住,商店更新应该是由于某些异步事件而发生的,以便启动更改检测。大多数情况下都是这样。但也有例外blog.angularindepth.com/...
async pipe
因为在订阅内部,我们通常有一些事情要做call setFromValues
do some comparison
..如果async
本身调用markForCheck
它,那么如果我们自己调用它会带来什么问题呢?但是同样,在ngOnInit
获取不同的数据时,我们通常会有2-3个或更多的选择器...而我们都调用markForCheck
了所有选择器。
cd.detectChanges()
将立即从当前组件一直到其后代运行更改检测。
cd.markForCheck()
将不会运行更改检测,但会将其祖先标记为需要运行更改检测。下次更改检测可在任何地方运行,它也将对已标记的那些组件运行。
cd.markForCheck()
。通常,更改会影响多个组件,并且会在某处调用更改检测。您实际上是在说:让我们确保在发生这种情况时也对该组件进行了更新。(该视图会在我编写的每个项目中立即更新,但不会在每个单元测试中更新)。cd.detectChanges()
当前 没有运行更改检测,请使用cd.markForCheck()
。detectChanges()
在这种情况下会出错。这可能意味着您试图编辑祖先组件的状态,这违背了围绕Angular进行变更检测的假设。detectChanges()
。markForCheck()
实际上可能不会及时更新您的视图。单元测试会影响您的视图,例如,fixture.detectChanges()
在应用程序本身不需要时,可能需要您手动调用。detectChanges()
因为您不必在组件的祖先上运行更改检测。