직장에서 문제가 발생했습니다. Angular 구성 요소 데이터를 실시간으로 뷰에 업데이트할 수 없습니다. 문제 자체는 비교적 해결하기 쉽지만 그래도 요약해서 기록합니다.
이유부터 먼저 이야기해볼까요. [관련 튜토리얼 추천: "angular tutorial"]
MainComponent:
@Component({ selector: 'main', template: ` <MenuComponent [isReport]="isReport"> </MenuComponent> `, changeDetection:ChangeDetectionStrategy.OnPush }) export class MainComponent { ... }
이제 MainComponent이 있는데, 다른 것을 참조해야 합니다. 이 구성 요소에는 Component MenuComponent가 있습니다.
import { Component, Input} from '@angular/core'; import { Subject, debounceTime } from 'rxjs'; @Component({ selector: 'movie', styles: ['div {border: 1px solid black}'], template: ` <div (mouseover)="mouseOver()"> <h3>{{ menu }}</h3> </div>` }) export class MovieComponent { @Input() isReport: boolean = false; menu: string = '我是Menu'; mouseOver$: Subject<any> = new Subject(); ngOnInit(): void { this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => { this.menu = 'New: ' + this.menu; }); } mouseOver(): void { this.mouseOver$.next(this.menu); } }
이 MenuComponent는 다른 페이지에서도 정상적으로 사용할 수 있으며, Menu 컴포넌트이기 때문에 mouseover 이벤트가 많이 존재하며, 이러한 이벤트도 정상적으로 동작할 수 있습니다. 그런데 이 MenuComponent를 MainComponent에 넣으면 mouseover 이벤트에 문제가 있는 것 같습니다. mouseover 이벤트를 디버깅한 후에는 코드가 제대로 실행되어 코드에는 문제가 없는 것 같습니다. . 이 구성 요소는 다른 페이지에 배치되어 완전히 정상적으로 작동하기 때문에 구성 요소 자체에 문제가 있는 것처럼 느껴지지 않습니다.
에서 나타나는 현상은 입니다.
메뉴에서 mouseover가 매우 이상하게 작동합니다. A로 가면 B의 데이터가 표시됩니다. 전체가 혼란스럽습니다. .
첫 번째 반응은 이것이 MainComponent의 mouseover 이벤트와 충돌할 수 있다는 것입니다.
다시 확인해 보니 문제가 없었습니다. 그런데 예상치 못한 이득이 있었습니다. 아 아 아, MainComponent 구성 요소는 OnPush 변경 감지 전략을 사용합니다. 다른 페이지는 잘 작동하지만 여기에 문제가 있습니다. 좋습니다. 문제는 OnPush에 의해 발생해야 합니다. 변경 감지 전략에 대해서는 파악하기 쉽지 않지만 이미 익숙합니다. 자, 이번 OnPush에 대해 간단히 살펴보겠습니다.
OnPush 전략
Angular에는 두 가지 변경 감지 전략이 있습니다. 하나는 기본이고 다른 하나는 OnPush입니다. OnPush 변경 감지 전략은 주로 성능을 향상시키는 것입니다. 구성 요소 데코레이터의 changeDetection을 OnPush로 설정하면 Angular는 변경 감지가 트리거될 때마다 이 구성 요소와 이 구성 요소의 모든 하위 구성 요소의 변경 감지를 건너뜁니다.
좋아요, 우리는 OnPush 변경 감지 전략이 무엇인지도 알고 있습니다. 이 전략은 현재 구성 요소와 하위 구성 요소의 변경 감지를 건너뜁니다. 즉, 이 컴포넌트의 속성값을 변경하면 해당 속성값이 뷰에 업데이트되지 않습니다. 즉, 컴포넌트 배열과 뷰가 일치하지 않습니다. 이제 이것을 알았으니 다시 돌아가서 MenuComponent를 살펴보겠습니다.
MainComponent의 변경 전략이 OnPush로 설정되었으므로 해당 하위 구성 요소의 변경 감지 전략은 건너뛰게 됩니다. 즉, MenuComponent의 변경 감지가 작동하지 않습니다. 그러나 메뉴를 조작하면 보기가 여전히 변경된다는 것을 알 수 있습니다. 무슨 일이야?
대부분의 사람들은 OnPush가 무엇인지 잠시 이해했지만 완전히 이해하지는 못했습니다. 계속 읽어보세요.
OnPush 전략에서 다음 상황은 구성 요소의 변경 감지를 트리거합니다.
OnPush 구성 요소 또는 해당 하위 구성 요소 중 하나가 BOM) click, mouseover, mouseleave, resize, keydown과 같은 이벤트는 변경 감지를 트리거합니다(구성 요소 트리의 모든 구성 요소에 대해).
OnPush 전략에서 다음 작업은 변경 감지를 트리거하지 않는다는 점에 유의해야 합니다.
OnPush 전략에도 불구하고 DOM/BOM 이벤트는 여전히 변경 감지를 트리거하므로 MenuComponent 뷰는 여전히 변경됩니다. 즉, 이 변경 감지가 작동 중입니다. 하지만 문제는 여전히 해결되지 않았습니다. 마우스를 올리면 메뉴가 여전히 혼란스러워집니다! 코드를 다시 살펴보겠습니다.
ngOnInit(): void { this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => { this.menu = 'New: ' + this.menu; }); }문제는
debounceTime으로 인해 발생합니다. 이전에 Rxjs의 원리를 소개할 때 이것이 비동기식이라고 말했습니다. 내가 전에 마스터했던 것이 마침내 도움이 되었습니다.
总结一下,就是mouseover是异步的,会触发变更检测,但是由于debounceTime是异步又嵌套了一下,debounceTime一般是用setTimeout来实现的。所以,debounceTime里的数据变化并不能及时的显示到视图中。终于找到问题的根源了。啦啦啦。问题找到了,那解决起来多easy啊。它不是不会触发变更检测吗,我就手动让它触发一下吧。
import { Component, Input, ChangeDetectorRef } from '@angular/core'; import { Subject, debounceTime } from 'rxjs'; @Component({ selector: 'movie', styles: ['div {border: 1px solid black}'], template: `...` }) export class MovieComponent { ... constructor(private cd: ChangeDetectorRef){} ngOnInit(): void { this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => { this.menu = 'New: ' + this.menu; this.cd.detectChanges(); }); } ... }
平时多注意知识积累,不能按照网上说的解决方案复制过来就解决了,遇到简单问题这样是没有问题的,遇到复杂的就没办法了;
当设置为Onpush策略时,要更加注意,用OnPush就是要减少变更检测的次数,就不要无论什么情况都detectChanges,或markForCheck,失去了意义,还是要规范使用;
要优雅实现代码,项目中居然还看到把父组件的ChangeDetectorRef作为输入属性传到子组件中,一看就不懂变更检测啊;
更多编程相关知识,请访问:编程教学!!
위 내용은 Angular 개발 문제 기록: 구성 요소 데이터를 실시간으로 뷰에 업데이트할 수 없습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!