Heim > Web-Frontend > js-Tutorial > Hauptteil

Angular-Entwicklungsproblemaufzeichnung: Komponentendaten können nicht in Echtzeit in der Ansicht aktualisiert werden

青灯夜游
Freigeben: 2022-12-08 20:25:15
nach vorne
2055 Leute haben es durchsucht

Ich bin bei der Arbeit auf ein Problem gestoßen: Angular Komponentendaten können nicht in Echtzeit auf die Ansicht aktualisiert werden. Das Problem selbst ist relativ einfach zu lösen, aber ich fasse es trotzdem zusammen und zeichne es auf.

Angular-Entwicklungsproblemaufzeichnung: Komponentendaten können nicht in Echtzeit in der Ansicht aktualisiert werden

Lass uns zuerst über den Grund sprechen. [Verwandte Tutorial-Empfehlung: „Angular-Tutorial“]

Ursprung des Problems


Hauptkomponente:

@Component({
  selector: 'main',
  template: `
    <MenuComponent [isReport]="isReport">
	  </MenuComponent>
 `,
  changeDetection:ChangeDetectionStrategy.OnPush
})
export class MainComponent {
  ...
}
Nach dem Login kopieren

Jetzt gibt es eine Hauptkomponente, und ich muss Verweisen Sie auf einen anderen in dieser Komponentenkomponente MenuComponent.

import { Component, Input} from &#39;@angular/core&#39;;
import { Subject, debounceTime } from &#39;rxjs&#39;;

@Component({
  selector: &#39;movie&#39;,
  styles: [&#39;div {border: 1px solid black}&#39;],
  template: `
    <div (mouseover)="mouseOver()">
      <h3>{{ menu }}</h3>
    </div>`
})
export class MovieComponent {
  @Input() isReport: boolean = false;
  menu: string = &#39;我是Menu&#39;;

  mouseOver$: Subject<any> = new Subject();

  ngOnInit(): void {
    this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => {
       this.menu = &#39;New: &#39; + this.menu;
    });
  }

  mouseOver(): void {
    this.mouseOver$.next(this.menu);
  }
}
Nach dem Login kopieren

Diese MenuComponent kann normal auf anderen Seiten verwendet werden, und da es sich um eine Menu-Komponente handelt, gibt es darauf viele Mouseover-Ereignisse, und diese Ereignisse können auch normal funktionieren. Wenn diese MenuComponent jedoch in MainComponent platziert wird, gibt es ein Problem mit dem Mouseover-Ereignis. Nach dem Debuggen des Mouseover-Ereignisses liegt meiner Meinung nach kein Problem mit dem Code vor. Da diese Komponente auf anderen Seiten platziert ist und sich völlig normal verhält, hat man nicht den Eindruck, dass das Problem bei der Komponente selbst liegt.

Das gezeigte Phänomen ist :

Mouseover

im Menü verhält sich sehr seltsam. Wenn Sie zu B gehen, werden die Daten von A angezeigt.

Die erste Reaktion ist: Könnte dies mit dem Mouseover-Ereignis in MainComponent in Konflikt stehen?

Ich habe es überprüft und kein Problem festgestellt. Aber es gab einen unerwarteten Gewinn, ah ah ah, die MainComponent-Komponente verwendet die OnPush-Änderungserkennungsstrategie. Kein Wunder, dass andere Seiten gut funktionieren, aber hier gibt es ein Problem. Ok, das Problem sollte durch OnPush verursacht werden. Was die Strategie zur Änderungserkennung betrifft, ist sie nicht leicht zu verstehen, aber sie ist bereits bekannt. Schauen wir uns diesen OnPush kurz an.

OnPush-Strategie

Angular verfügt über zwei Änderungserkennungsstrategien, eine ist Standard und die andere ist dieser OnPush. Die Änderungserkennungsstrategie von OnPush dient hauptsächlich der Verbesserung der Leistung. Wenn wir die changeDetection des Komponentendekorators auf OnPush setzen, überspringt Angular die Änderungserkennung dieser Komponente und aller Unterkomponenten dieser Komponente jedes Mal, wenn die Änderungserkennung ausgelöst wird.

Okay, wir wissen auch, was die Änderungserkennungsstrategie von OnPush ist. Sie überspringt die Änderungserkennung der aktuellen Komponente und ihrer Unterkomponenten. Mit anderen Worten, wenn Sie die Eigenschaftswerte dieser Komponente ändern, werden diese Eigenschaftswerte nicht in der Ansicht aktualisiert, dh das Komponentenarray und die Ansicht sind inkonsistent. Nachdem wir das nun wissen, werfen wir einen Blick zurück auf MenuComponent.

Da die Änderungsstrategie von MainComponent auf OnPush eingestellt ist, wird die Änderungserkennungsstrategie ihrer Unterkomponente übersprungen, d. h. die Änderungserkennung von MenuComponent funktioniert nicht. Sie werden jedoch feststellen, dass sich die Ansicht dennoch ändert, wenn Sie das Menü bedienen. Was ist los?

Die meisten Leute haben vielleicht eine Minute damit verbracht, zu verstehen, was OnPush ist, aber sie haben es nicht wirklich verstanden. Lesen Sie weiter.

Unter der OnPush-Strategie lösen die folgenden Situationen die Änderungserkennung der Komponente aus:

Die aktuelle Komponente oder eine ihrer Unterkomponenten löst ein Ereignis aus

Wenn die OnPush-Komponente oder eine ihrer Unterkomponenten auslöst (DOM/ BOM) Ereignisse wie click, mouseover, mouseleave, resize, keydown lösen eine Änderungserkennung aus (für alle Komponenten im Komponentenbaum).

Es ist zu beachten, dass in der OnPush-Strategie die folgenden Vorgänge keine Änderungserkennung auslösen:

  • setTimeout()

  • setInterval()

  • Promise.resolve().then()

  • this.http.get('...').subscribe()

Es stellt sich heraus, dass trotz der OnPush-Strategie das DOM/BOM-Ereignis immer noch eine Änderungserkennung auslöst, also MenuComponent Die Ansicht ändert sich weiterhin, das heißt, diese Änderungserkennung funktioniert. Aber das Problem ist immer noch nicht gelöst, das Menü wird beim Mouseover immer noch verwirrt sein! Schauen wir uns den Code noch einmal an.

ngOnInit(): void {
    this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => {
       this.menu = &#39;New: &#39; + this.menu;
    });
}
Nach dem Login kopieren

Das Problem wird durch debounceTime verursacht. Als ich zuvor das Prinzip von Rxjs vorstellte, sagte ich, dass dies asynchron sei. Was ich zuvor beherrschte, erwies sich endlich als nützlich.

总结一下,就是mouseover是异步的,会触发变更检测,但是由于debounceTime是异步又嵌套了一下,debounceTime一般是用setTimeout来实现的。所以,debounceTime里的数据变化并不能及时的显示到视图中。终于找到问题的根源了。啦啦啦。问题找到了,那解决起来多easy啊。它不是不会触发变更检测吗,我就手动让它触发一下吧。

import { Component, Input, ChangeDetectorRef } from &#39;@angular/core&#39;;
import { Subject, debounceTime } from &#39;rxjs&#39;;

@Component({
  selector: &#39;movie&#39;,
  styles: [&#39;div {border: 1px solid black}&#39;],
  template: `...`
})
export class MovieComponent {
  ...

  constructor(private cd: ChangeDetectorRef){}

  ngOnInit(): void {
    this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => {
       this.menu = &#39;New: &#39; + this.menu;

       this.cd.detectChanges();
    });
  }

  ...
}
Nach dem Login kopieren

总结


  • 平时多注意知识积累,不能按照网上说的解决方案复制过来就解决了,遇到简单问题这样是没有问题的,遇到复杂的就没办法了;

  • 当设置为Onpush策略时,要更加注意,用OnPush就是要减少变更检测的次数,就不要无论什么情况都detectChanges,或markForCheck,失去了意义,还是要规范使用;

  • 要优雅实现代码,项目中居然还看到把父组件的ChangeDetectorRef作为输入属性传到子组件中,一看就不懂变更检测啊;

更多编程相关知识,请访问:编程教学!!

Das obige ist der detaillierte Inhalt vonAngular-Entwicklungsproblemaufzeichnung: Komponentendaten können nicht in Echtzeit in der Ansicht aktualisiert werden. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!