【问题标题】:Angular2 observable change detection template updateAngular2 可观察变化检测模板更新
【发布时间】:2016-09-25 11:41:06
【问题描述】:

出于性能原因,我正在尝试在我的组件上设置手动更改检测。

应用程序的结构:应用程序 -> 书籍 -> 页面

我在 AppComponent 中订阅了一个 observable,然后运行 ​​ChangeDetectorRef 的“markForCheck”方法。

这似乎触发了 BookComponent(我标记为更新的组件的子组件)中的 ngAfterContentChecked 方法。

这让我相信父组件中的“markForCheck”也会更新所有子组件。

但是,即使在子组件(BookComponent)中执行了 ngAfterContentChecked,该组件的模板也不会更新!

我是否应该倾听每个孩子的 observable(有时在组件层次结构中的几个层次)?还是我做错了什么?以及为什么即使模板没有更新,ngAfterContentChecked 也会在子组件中执行?

一些相关代码。

@Component({
    selector: 'app',
    directives: [BookComponent],
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: `
        <book *ngIf="_book" [book]="_book" [style.height]="_availableDimensions.height+'px'" (window:resize)="onResize($event)"></book>
        <footer id="footer"></footer>
    `
})

export class PlayerComponent {
    ngOnInit() {
        this.initScale();
    }

initScale(){
        this._playerService.availableDimensions$.subscribe(
            availableDimensions => {
                // set local availableDimensions variable
                this._availableDimensions = availableDimensions;
                this._cd.markForCheck();
            }
        );
    }
}



@Component({
    selector: 'book',
    directives: [PageComponent],
    changeDetection: ChangeDetectionStrategy.OnPush,
    template: `
        <div id="pageScrollZone">
            <div id="pageHolder" [ngStyle]="pageHolderStyles()"></div>
        </div>
    `
})

export class BookComponent {
    constructor(
            private _cd: ChangeDetectorRef,
            private _playerService: PlayerService,
            private _config: Config
    ){}

    ngAfterContentChecked(){
// This part does execute when the observable changes
        let date = new Date();
        console.log('BOOK: '+date.getHours()+':'+date.getMinutes()+':'+date.getSeconds());
    }

    pageHolderStyles(){
// This part does NOT execute when the observable changes
        let styles = {
            marginTop: this._currentMargin.y+'px',
            transform: 'scale('+ (this._baseZoom * this._currentZoomLevel) +')'
        }

        return styles;
    }
}

【问题讨论】:

  • 文字很便宜 - 给我们看一些代码 ;-) 理想情况下是一个允许复制的 plunker。

标签: angular observable angular2-changedetection


【解决方案1】:

Sooo...两件快速的事情..

首先,当您使用 markForCheck() 时,它会在组件 ITSELFROOT COMPONENT 之间标记 Angular 应该运行更改检测的路径。 p>

From a great Thoughtram Article:

"我们可以通过依赖访问组件的 ChangeDetectorRef 注入,它带有一个名为 markForCheck() 的 API。这种方法 正是我们需要的!它标记了从我们的组件到的路径 要检查下一次更改检测运行的根目录。”

因此,当您触发它时,它不会查看自己的子组件,而是查看根组件。如果它的孩子也是 onPush 他们将忽略它的更新。

我是否应该倾听每个孩子的 observable(有时在组件层次结构中的几个层次)?

仅当您希望所有元素都显式 onPush 时。 我的猜测是您希望 Pages 如果它的父级自动更新...那么您很幸运!如果您在页面组件上使用 标准策略,并在 Book 上使用 onPush 策略,当检测沿着树向下运行时,它将 跳过该分支,即使子组件是正常组件。 Source:Victor Savkin

所以你不必深入聆听观察者的声音,只要你想休息的地方。 onPush 中的每个组件都不能保证性能提升,如果您必须欺骗它使其工作。在大多数情况下,只需阻塞关键节点就足够了。

第二件事是关于 ngAfterContentChecked 这是一个已知的错误:

(完全一样)https://github.com/angular/angular/issues/7055

(相关,更好的讨论)https://github.com/angular/angular/issues/7054

所以他们知道了,它实际上并不是在运行检测,而是在触发回调......

【讨论】:

    猜你喜欢
    • 2017-12-03
    • 2016-04-26
    • 2016-09-29
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多