Maison  >  Article  >  interface Web  >  Enregistrement de problème de développement angulaire : les données des composants ne peuvent pas être mises à jour dans la vue en temps réel

Enregistrement de problème de développement angulaire : les données des composants ne peuvent pas être mises à jour dans la vue en temps réel

青灯夜游
青灯夜游avant
2022-12-08 20:25:152025parcourir

J'ai rencontré un problème au travail : les données des composants angulaires ne peuvent pas être mises à jour dans la vue en temps réel. Le problème lui-même est relativement facile à résoudre, mais je le résume et l'enregistre quand même.

Enregistrement de problème de développement angulaire : les données des composants ne peuvent pas être mises à jour dans la vue en temps réel

Parlons d’abord de la raison. [Recommandation de tutoriel associée : "Tutoriel angulaire"]

Origine du problème


MainComponent :

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

Maintenant, il y a un MainComponent, et je dois en référencer un autre un dans ce composant Composant 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);
  }
}

Ce MenuComponent peut être utilisé normalement sur d'autres pages, et comme il s'agit d'un composant Menu, il contient de nombreux événements mouseover, et ces événements peuvent également fonctionner normalement. Cependant, ce MenuComponent est placé dans MainComponent, et il y a un problème avec l'événement mouseover Après avoir débogué l'événement mouseover, le code est exécuté correctement et je pense qu'il n'y a aucun problème avec le code. . Étant donné que ce composant est placé dans d’autres pages et se comporte tout à fait normalement, il ne semble pas que le problème provienne du composant lui-même. Le phénomène montré par

est  : 

le survol de la souris

dans Menu se comporte de manière très étrange. Lorsque vous passez à A, les données de B sont affichées. Lorsque vous passez à B, les données de A sont affichées. .

La première réaction est la suivante : cela pourrait-il entrer en conflit avec l'événement mouseover dans MainComponent ?

Je l'ai vérifié à nouveau et je n'ai trouvé aucun problème. Mais il y a eu un gain inattendu, ah ah ah, le composant MainComponent utilise la stratégie de détection de changement OnPush Pas étonnant que d'autres pages fonctionnent bien, mais il y a un problème ici. Ok, le problème devrait être causé par OnPush. Concernant la stratégie de détection des changements, elle n'est pas facile à appréhender. Allez, faisons un petit tour d'horizon de cet OnPush.

Stratégie OnPush

Angular a deux stratégies de détection de changement, l'une est par défaut et l'autre est OnPush. La stratégie de détection des changements OnPush vise principalement à améliorer les performances. Lorsque nous définissons la changeDetection du décorateur de composant sur OnPush, Angular ignorera la détection de changement de ce composant et de tous les sous-composants de ce composant à chaque fois que la détection de changement est déclenchée.

D'accord, nous savons également ce qu'est la stratégie de détection des changements OnPush, elle ignorera la détection des changements du composant actuel et de ses sous-composants. En d'autres termes, si vous modifiez les valeurs de propriété de ce composant, ces valeurs de propriété ne seront pas mises à jour dans la vue, c'est-à-dire que le tableau de composants et la vue sont incohérents. Maintenant que nous savons cela, revenons en arrière et jetons un œil à MenuComponent.

Étant donné que la stratégie de changement de MainComponent est définie sur OnPush, la stratégie de détection de changement de son sous-composant sera ignorée, c'est-à-dire que la détection de changement de MenuComponent ne fonctionnera pas. Cependant, vous constaterez que la vue changera toujours lorsque vous utiliserez le menu. Que se passe-t-il?

La plupart des gens ont peut-être passé une minute à comprendre ce qu'est OnPush, mais ils ne l'ont pas complètement compris. Continuez à lire.

Dans le cadre de la stratégie OnPush, les situations suivantes déclencheront la détection de changement du composant :

Le composant courant ou l'un de ses sous-composants déclenche un événement

Si le composant OnPush ou l'un de ses sous-composants déclenche (DOM/ BOM) tels que click, mouseover, mouseleave, resize, keydown déclencheront la détection des modifications (pour tous les composants de l'arborescence des composants).

Il est à noter que dans la stratégie OnPush, les opérations suivantes ne déclencheront pas la détection de changement :

  • setTimeout()

  • setInterval()

  • Promise.resolve().then()

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

Il s'avère que malgré la stratégie OnPush, l'événement DOM/BOM déclenchera toujours la détection de changement, donc MenuComponent La vue changera toujours, c'est-à-dire que cette détection de changement fonctionne. Mais le problème n'est toujours pas résolu, le Menu sera toujours confus au passage de la souris ! Regardons à nouveau le code.

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

Le problème est causé par debounceTime Quand j'ai présenté le principe de Rxjs auparavant, j'ai dit que c'était asynchrone. Ce que j'avais maîtrisé auparavant s'est finalement avéré utile.

总结一下,就是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();
    });
  }

  ...
}

总结


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

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

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

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer