angular – 为什么我们需要`ngDoCheck`

前端之家收集整理的这篇文章主要介绍了angular – 为什么我们需要`ngDoCheck`前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我似乎无法弄清楚为什么我需要ngDoCheck生命周期钩子而不是简单的通知,特别是如何在其中编写代码在变化检测方面有所不同。我发现的大多数示例都显示了无用的示例,如 this one,具有一堆日志记录功能

此外,在生成的类中,我没有看到它被用于除简单通知之外的其他内容

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,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;
    };
这篇伟大的文章 If you think ngDoCheck means your component is being checked — read this article深入解释了错误

此答案的内容基于角度版本2.x.x.对于最新版本4.x.x,请参阅this post

互联网上没有关于变更检测内部工作的任何内容,因此我不得不花费大约一周的时间来调试源代码,因此这个答案对于细节来说将是非常技术性的。

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

运行更改检测周期时,每个父视图都会检查是否应对子视图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

这指向子视图。因此,如果cdMode是ChangeDetectorStatus.Checked = 1,则由于此行而跳过针对直接子节点及其所有后代的更改检测。

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

什么changeDetection:ChangeDetectionStrategy.OnPush做的只是将cdMode设置为ChangeDetectorStatus.CheckOnce = 0,所以在第一次更改检测后,子视图的cdMode将因为this code而设置为ChangeDetectorStatus.Checked = 1:

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

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

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

constructor(private _changeRef: ChangeDetectorRef) {   }

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

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

查看完整的示例here in the sources,但这是它的要点:

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

第二个选项是在视图本身上调用detectChanges,如果cdMode不是ChangeDetectorStatus.Checked或ChangeDetectorStatus.Errored,则在当前视图上调用run change detection。由于使用onPush角度将cdMode设置为ChangeDetectorStatus.CheckOnce,angular将运行更改检测。

因此,ngDoCheck不会覆盖已更改的检测,只需在每个更改的检测周期调用它,并且唯一的工作是将当前视图cdMode设置为checkOnce,以便在下一个更改检测周期中检查更改。有关详细信息,请参阅this answer。如果当前视图的更改检测模式为checkAlways(如果未使用onPush策略,则默认设置),ngDocCheck似乎没用。

原文链接:https://www.f2er.com/angularjs/143869.html

猜你在找的Angularjs相关文章