par*_*ent 146 angular2-changedetection angular
ChangeDetectorRef.markForCheck()和之间有什么区别ChangeDetectorRef.detectChanges()?
我只在SO上找到了关于NgZone.run()这两个函数之间的差异的信息,但不是这两个函数之间的区别.
对于仅提及文档的答案,请说明一些实际场景,以选择其中一个.
Mil*_*lad 195
来自docs:
detectChanges():void
这意味着,如果存在模型(您的类)中的任何内容发生更改但未反映视图的情况,您可能需要通知Angular检测这些更改(检测本地更改)并更新视图.
可能的情况可能是:
2-更新已经发生,但它没有进入Angular Zone,因此,Angular不知道它.
就像第三方功能更新了您的模型并且您希望在此之后更新视图一样.
someFunctionThatIsRunByAThirdPartyCode(){
yourModel.text = "new text";
}
Run Code Online (Sandbox Code Playgroud)
因为此代码在Angular的区域之外(可能),您很可能需要确保检测更改并更新视图,因此:
myFunction(){
someFunctionThatIsRunByAThirdPartyCode();
// Let's detect the changes that above function made to the model which Angular is not aware of.
this.cd.detectChanges();
}
Run Code Online (Sandbox Code Playgroud)
注意:
还有其他方法可以完成上述工作,换句话说,还有其他方法可以将这种变化带入Angular变更周期.
**你可以在zone.run中包装第三方函数:
myFunction(){
this.zone.run(this.someFunctionThatIsRunByAThirdPartyCode);
}
Run Code Online (Sandbox Code Playgroud)
**您可以将函数包装在setTimeout中:
myFunction(){
setTimeout(this.someFunctionThatIsRunByAThirdPartyCode,0);
}
Run Code Online (Sandbox Code Playgroud)
3-在某些情况下,您可以在change detection cycle完成后更新模型,在这种情况下,您会遇到这个可怕的错误:
"检查后表情发生了变化";
这通常意味着(来自Angular2语言):
我看到你的模型中的一个更改是由我接受的方式之一(事件,XHR请求,setTimeout和......)然后我运行我的更改检测来更新你的视图我完成了它,但是那时还有另一个在您的代码中再次更新模型的功能,我不想再次运行我的更改检测,因为不再像AngularJS那样进行脏检查:D我们应该使用单向数据流!
你肯定会遇到这个错误:P.
几种方法来解决它:
1- 正确的方法:确保更新在更改检测周期内(Angular2更新是发生一次的单向流,不要在此之后更新模型并将代码移动到更好的位置/时间).
2- 懒惰方式:在更新后运行detectChanges()使angular2高兴,这绝对不是最好的方法,但是当你问到可能的场景是什么时,这就是其中之一.
这样你就说:我真诚地知道你运行了变更检测,但是我希望你再次这样做,因为我必须在完成检查后立即更新.
3-将代码放入a中setTimeout,因为它setTimeout是按区域修补的,并detectChanges在完成后运行.
来自文档
Run Code Online (Sandbox Code Playgroud)markForCheck() : void
这主要是在需要时ChangeDetectionStrategy你的组件是OnPush.
OnPush本身意味着,只有在发生以下任何情况时才运行更改检测:
1-如果@Input属性的引用完全改变,则组件的一个@inputs已完全替换为新值,或者简单地放置.
所以,如果ChangeDetectionStrategy您的组件是OnPush,然后你必须:
var obj = {
name:'Milad'
};
Run Code Online (Sandbox Code Playgroud)
然后你更新/改变它像:
obj.name = "a new name";
Run Code Online (Sandbox Code Playgroud)
这不会更新obj引用,因此更改检测不会运行,因此视图不反映更新/突变.
在这种情况下,您必须手动告诉Angular检查并更新视图(markForCheck);
所以,如果你这样做:
obj.name = "a new name";
Run Code Online (Sandbox Code Playgroud)
你需要这样做:
this.cd.markForCheck();
Run Code Online (Sandbox Code Playgroud)
相反,bellow会导致更改检测运行:
obj = {
name:"a new name"
};
Run Code Online (Sandbox Code Playgroud)
这完全取代了以前的obj用新的{};
2-事件已触发,如点击或某些事情或任何子组件发出事件.
事件如:
简而言之:
detectChanges()在角度运行变更检测后更新模型时使用,或者如果更新根本没有处于角度世界中.
使用markForCheck()如果您使用的OnPush和你绕过ChangeDetectionStrategy通过突变的一些数据,或者你已经更新了内部模型的setTimeout ;
Max*_*kyi 85
两者之间的最大区别在于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()); <------------------
Run Code Online (Sandbox Code Playgroud)
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;
}
}
Run Code Online (Sandbox Code Playgroud)
组件的实际更改检测未进行调度,但将在未来发生时(作为当前或下一个CD周期的一部分),即使它们具有分离的更改检测器,也将检查父组件视图.可以通过使用cd.detach()或通过指定OnPush变化检测策略来分离变化检测器.所有本机事件处理程序都标记所有父组件视图以进行检查.
这种方法通常用于ngDoCheck生命周期钩子中.您可以在" 如果您认为ngDoCheck意味着正在检查组件"中阅读更多内容- 请阅读本文.
有关更多详细信息,请参阅Angular中有关更改检测的所有信息.
Kev*_*eal 18
cd.detectChanges() 将立即从当前组件向下通过其后代运行更改检测。
cd.markForCheck()不会运行变更检测,但将其祖先标记为需要运行变更检测。下次更改检测在任何地方运行时,它也会为那些被标记的组件运行。
cd.markForCheck(). 通常,更改会影响多个组件,并且会在某处调用更改检测。您实际上是在说:让我们确保在发生这种情况时也更新此组件。(视图会在我编写的每个项目中立即更新,但不是在每个单元测试中)。cd.detectChanges()没有运行更改检测,请使用. 在这种情况下会出错。这可能意味着您尝试编辑祖先组件的状态,这违背了 Angular 的更改检测是围绕设计的假设。 cd.markForCheck()detectChanges()detectChanges(). markForCheck()实际上可能不会及时更新您的视图。单元测试会影响您的视图,例如,可能需要您fixture.detectChanges()在应用程序本身不需要时手动调用。detectChanges()因为您不会不必要地在组件的祖先上运行更改检测。Ste*_*rov 16
我创建了一个 4分钟的截屏视频来解释markForCheck()和detectChanges()之间的区别- https://www.youtube.com/watch?v=OcphK_aEd7I
| 归档时间: |
|
| 查看次数: |
54728 次 |
| 最近记录: |