本文介绍了我们为什么需要`ngDoCheck`的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

除了简单的通知外,我似乎无法弄清楚为什么我需要ngDoCheck生命周期挂钩,尤其是在其中编写代码如何对变更检测产生影响.我发现的大多数示例都显示了无用的示例,例如此示例,具有大量的日志记录功能.

I can't seem to figure out why I need ngDoCheck lifecycle hook other than for simple notification, particularly how writing code inside of it makes a difference as regard to change detection. Most of the examples I've found show useless examples, like this one, with a bunch of logging functionality.

此外,在生成的类中,除了简单的通知,我看不到它被用于其他用途:

Also, in the generated classes I don't see it being used for something else other than simple notification:

conmponent/wrapper.ngfactory.js

conmponent/wrapper.ngfactory.js

Wrapper_AppComponent.prototype.ngDoCheck = function(view,el,throwOnChange) {
  var self = this;
  var changed = self._changed;
  self._changed = false;
  if (!throwOnChange) {
    if (changed) {
      jit_setBindingDebugInfoForChanges1(view.renderer,el,self._changes);
      self._changes = {};
    }
    self.context.ngDoCheck(); <----------- this calls ngDoCheck on the component
                                           but the result is not used
                                           anywhere and no params are passed
      }
      return changed;
    };

推荐答案

这篇很棒的文章如果您认为ngDoCheck表示正在检查您的组件-请阅读本文深入解释错误.

This great article If you think ngDoCheck means your component is being checked — read this article explains the error in depth.

此答案的内容基于2.x.x版本.有关最新版本4.xx,请参见这篇文章.

The contents of this answer is based on the angular version 2.x.x. For the most recent version 4.x.x see this post.

更改检测的内部工作原理在互联网上没有任何内容,因此我不得不花大约一周的时间调试源代码,因此此答案在细节上将是非常技术性的.

There is nothing on the internet on the inner workings of change detection, so I had to spend about a week debugging sources, so this answer will be pretty technical on details.

角度应用程序是视图(AppView类,由编译器生成的特定于组件的类扩展).每个视图都有一个更改检测模式,该模式位于cdMode属性中. cdMode的默认值为ChangeDetectorStatus.CheckAlways,即cdMode = 2.

An angular application is a tree of views (AppView class that is extended by the Component specific class generated by the compiler). Each view has a change detection mode that lives in cdMode property. The default value for cdMode is ChangeDetectorStatus.CheckAlways, which is cdMode = 2.

运行更改检测周期时,每个父视图都会检查是否应在子视图上执行更改检测此处:

When a change detection cycle runs, each parent view checks whether it should perform change detection on the child view here:

  detectChanges(throwOnChange: boolean): void {
    const s = _scope_check(this.clazz);
    if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;
    if (this.cdMode === ChangeDetectorStatus.Destroyed) {
      this.throwDestroyedError('detectChanges');
    }
    this.detectChangesInternal(throwOnChange); <---- performs CD on child view

其中this指向child视图.因此,如果cdModeChangeDetectorStatus.Checked=1,则由于此行,将跳过对直接子代及其所有后代的更改检测.

where this points to the child view. So if cdMode is ChangeDetectorStatus.Checked=1, the change detection is skipped for the immediate child and all its descendants because of this line.

if (this.cdMode === ChangeDetectorStatus.Checked ||
        this.cdMode === ChangeDetectorStatus.Errored)
      return;

changeDetection: ChangeDetectionStrategy.OnPush所做的只是将cdMode设置为ChangeDetectorStatus.CheckOnce = 0,因此在第一次运行更改检测之后,由于此代码:

What changeDetection: ChangeDetectionStrategy.OnPush does is simply sets cdMode to ChangeDetectorStatus.CheckOnce = 0, so after the first run of change detection the child view will have its cdMode set to ChangeDetectorStatus.Checked = 1 because of this code:

if (this.cdMode === ChangeDetectorStatus.CheckOnce)
     this.cdMode = ChangeDetectorStatus.Checked;

这意味着下次更改检测周期开始时,将不会对子视图执行更改检测.

Which means that the next time a change detection cycle starts there will be no change detection performed for the child view.

对于这种视图,如何运行更改检测的选项很少.首先是将子视图的cdMode更改为ChangeDetectorStatus.CheckOnce,这可以使用ngDoCheck生命周期挂钩中的this._changeRef.markForCheck()完成:

There are few options how to run change detection for such view. First is to change child view's cdMode to ChangeDetectorStatus.CheckOnce, which can be done using this._changeRef.markForCheck() in ngDoCheck lifecycle hook:

  constructor(private _changeRef: ChangeDetectorRef) {   }

  ngDoCheck() {
    this._changeRef.markForCheck();
  }

这只是将当前视图及其父视图的cdMode更改为ChangeDetectorStatus.CheckOnce,因此,下次执行更改检测时,将检查当前视图.

This simply changes cdMode of the current view and its parents to ChangeDetectorStatus.CheckOnce, so next time the change detection is performed the current view is checked.

检查完整示例在来源中,但这是要点:

Check a full example here in the sources, but here is the gist of it:

      constructor(ref: ChangeDetectorRef) {
        setInterval(() => {
          this.numberOfTicks ++
          // the following is required, otherwise the view will not be updated
          this.ref.markForCheck();
          ^^^^^^^^^^^^^^^^^^^^^^^^
        }, 1000);
      }

第二个选项是在视图本身上调用detectChanges,该视图将.由于使用onPush角度设置cdModeChangeDetectorStatus.CheckOnce,角度将运行更改检测.

The second option is call detectChanges on the view itself which will run change detection on the current view if cdMode is not ChangeDetectorStatus.Checked or ChangeDetectorStatus.Errored. Since with onPush angular sets cdMode to ChangeDetectorStatus.CheckOnce, angular will run the change detection.

因此,ngDoCheck不会覆盖更改的检测,它只是在每个更改的检测周期被调用,唯一的工作就是将当前视图cdMode设置为checkOnce,以便在下一个更改检测周期中进行检查变化.有关详细信息,请参见此答案.如果当前视图的更改检测模式为checkAlways(如果不使用onPush策略,则默认设置),则ngDoCheck似乎毫无用处.

So ngDoCheck doesn't override the changed detection, it's simply called on every changed detection cycle and it's only job is to set current view cdMode as checkOnce, so that during next change detection cycle it's checked for the changes. See this answer for details. If the current view's change detection mode is checkAlways (set by default if onPush strategy is not used), ngDoCheck seem to be of no use.

这篇关于我们为什么需要`ngDoCheck`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-23 14:21