I encountered a problem at work: AngularThe component data cannot be updated to the view in real time. The problem itself is relatively easy to solve, but I still summarize and record it.
Let’s talk about the cause first. [Related tutorial recommendations: "angular tutorial"]
##MainComponent:
@Component({ selector: 'main', template: ` <MenuComponent [isReport]="isReport"> </MenuComponent> `, changeDetection:ChangeDetectionStrategy.OnPush }) export class MainComponent { ... }
MainComponent, and I need to reference another component MenuComponent in this component.
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 is normal to use on other pages, and because it is a Menu component, there are many mouseover events on it , these events also work fine. However, when this MenuComponent is placed in MainComponent, there is a problem with the mouseover event. After debugging the mouseover event, the code is executed correctly. I feel like there is nothing wrong with the code. Because this component is placed in other pages and behaves completely normally, it doesn't feel like the problem is with the component itself.
The phenomenon is : mouseover
inbehaves very strangely. When you over to A, the data of B is displayed. , when you go over to B, the data of A is displayed, and the whole thing is messed up.
The first reaction is, will this conflict with themouseover event in MainComponent?
I checked it again and found no problem. But there was an unexpected gain, ah ah, theMainComponent component uses the OnPush change detection strategy. No wonder other pages work fine, but there is a problem here. Ok, the problem should be caused by OnPush. Regarding the change detection strategy, it is not easy to grasp, but it is already familiar. Come on, let’s take a brief look at this OnPush.
OnPush strategy
Angular has two change detection strategies, one is Default, and the other is OnPush. The OnPush change detection strategy is mainly to improve performance. When we set thechangeDetection of the component decorator to OnPush, Angular will skip the change detection of the component and all subcomponents of the component every time change detection is triggered.
Okay, we also know what the OnPush change detection strategy is. It will skip the change detection of the current component and its subcomponents. In other words, if you change the property values of this component, these property values will not be updated to the view, that is, the component array and the view are inconsistent. Now that we know this, let’s go back and take a look atMenuComponent.
Since the change strategy ofMainComponent is set to OnPush, the change detection strategy of its sub-components will be skipped, that is, MenuComponent change detection Doesn't work anymore. However, you will find that the view will still change when you operate the Menu. How is this going?
Most people may have spent a minute understanding whatOnPush is, but they did not understand it thoroughly. Read on.
Under theOnPush strategy, the following situations will trigger component change detection:
One of the current components or subcomponents triggers an event If theOnPush component or one of its subcomponents fires a (DOM/BOM) event, such as click, mouseover, mouseleave , resize, keydown, then change detection will be triggered (for all components in the component tree).
It should be noted that in theOnPush strategy, the following operations will not trigger change detection:
strategy, the DOM/BOM event will still trigger change detection , so the view of MenuComponent will still change, that is, this change detection works. But the problem is still not solved, the Menu will still be confused when mouseover! Let’s look at the code again. ngOnInit(): void {
this.mouseOver$.pipe(debounceTime(250)).subscribe((data) => {
this.menu = 'New: ' + this.menu;
});
}
. When I introduced the principle of Rxjs before, I said that this is asynchronous. What I had mastered before finally came in handy. 总结一下,就是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作为输入属性传到子组件中,一看就不懂变更检测啊;
更多编程相关知识,请访问:编程教学!!
The above is the detailed content of Angular development problem record: Component data cannot be updated to the view in real time. For more information, please follow other related articles on the PHP Chinese website!